This commit is contained in:
2026-06-30 23:57:40 +08:00
parent d9f4f592ba
commit ba01ce2df7
32 changed files with 3806 additions and 1022 deletions
+119 -39
View File
@@ -11,7 +11,7 @@ using UnityEngine.UI;
public class UserInfoPanel : SubUIBase
{
[Header("基础信息")]
public Image sprite_Avatar;
public Image sprite_Avatar; // 显示已保存的用户头像(点使用后更新)
public Button btn_ChangeUser;
public TextMeshProUGUI tMPText_Name;
public TextMeshProUGUI tMPText_ID;
@@ -22,30 +22,23 @@ public class UserInfoPanel : SubUIBase
public TextMeshProUGUI tMPText_PhoneNumber;
[Header("头像选择")]
public GameObject prefab_AvatarItem; // 头像选项预制体(含 Image + Button)
public Image img_ShowAvatar; // 预览头像(选中即更新)
public Toggle prefab_AvatarItem; // 头像选项预制体(child0=Image, child2=选中对号)
public Button btn_UseAvatar; // 确认使用按钮
public Transform parent_AvatarList;
GameManager gameManager => GameManager.Instance;
private List<Toggle> _avatarToggles = new List<Toggle>();
private string _pendingAvatarName; // 选中的待确认头像名
public override void Awake()
{
base.Awake();
btn_ChangeUser.onClick.AddListener(() =>
{
// 退出登录 → 返回登录界面
gameManager.Logout(
// () =>
//{
// UIManager.Instance.Show<LoadingPanel>(null, () =>
// {
// SceneMgr.Instance.LoadScene("Login", () =>
// {
// UIManager.Instance.ShowUI<LoginPanel>();
// });
// });
//}
);
gameManager.Logout();
});
btn_UseAvatar.onClick.AddListener(OnClickUseAvatar);
}
protected override void OnShow(object args = null)
@@ -53,7 +46,16 @@ public class UserInfoPanel : SubUIBase
base.OnShow(args);
InitInformation();
BuildAvatarList();
// 监听头像变更
gameManager.OnAvatarChanged += OnAvatarChanged;
}
protected override void OnHide()
{
base.OnHide();
gameManager.OnAvatarChanged -= OnAvatarChanged;
// 清理 toggle 列表
_avatarToggles.Clear();
}
// ==================== 基础信息 ====================
@@ -62,8 +64,9 @@ public class UserInfoPanel : SubUIBase
{
tMPText_Name.color = gameManager.user.BaseInfo.isRedName ? Color.red : Color.white;
// 加载当前用户头像
// 初始化两个头像(正式头像 和 预览头像)都为当前已保存的头像
LoadAvatarImage(sprite_Avatar, gameManager.user.BaseInfo.avatarUrl);
LoadAvatarImage(img_ShowAvatar, gameManager.user.BaseInfo.avatarUrl);
tMPText_Name.text = gameManager.user.BaseInfo.userName;
tMPText_ID.text = gameManager.user.BaseInfo.number;
@@ -76,9 +79,6 @@ public class UserInfoPanel : SubUIBase
// ==================== 头像加载 ====================
/// <summary>
/// 加载头像图片:判断 avatarUrl 是本地ID还是网络URL
/// </summary>
private void LoadAvatarImage(Image target, string avatarUrl)
{
if (target == null) return;
@@ -107,41 +107,121 @@ public class UserInfoPanel : SubUIBase
// 清空旧列表
for (int i = parent_AvatarList.childCount - 1; i >= 0; i--)
Destroy(parent_AvatarList.GetChild(i).gameObject);
_avatarToggles.Clear();
// 从 GameManager 获取所有头像缓存
// 获取所有头像
gameManager.InitAvatarCache();
var allSprites = Resources.LoadAll<Sprite>("Avatar");
string currentAvatar = gameManager.user.BaseInfo.avatarUrl;
foreach (var sprite in allSprites)
{
var obj = Instantiate(prefab_AvatarItem, parent_AvatarList);
// 设置头像图片
var img = obj.GetComponentInChildren<Image>();
if (img != null)
img.sprite = sprite;
// 点击按钮 → 应用头像
var btn = obj.GetComponent<Button>();
if (btn != null)
// 1. 设置列表项的小头像 (child0 = Image)
if (obj.transform.childCount > 0)
{
string avatarName = sprite.name; // 文件名即 ID
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(() => ApplyAvatar(avatarName));
var img = obj.transform.GetChild(0).GetComponent<Image>();
if (img != null) img.sprite = sprite;
}
// 2. 获取对号图标 (child2)
Transform checkMark = null;
if (obj.transform.childCount > 2)
{
checkMark = obj.transform.GetChild(2);
// 初始隐藏
checkMark.gameObject.SetActive(false);
}
var toggle = obj.GetComponent<Toggle>();
if (toggle != null)
{
// 关键:禁用 Toggle 自动过渡,防止自动显示 Graphic
toggle.transition = Selectable.Transition.None;
_avatarToggles.Add(toggle);
string avatarName = sprite.name;
// 判断是否是当前已装备的头像
bool isCurrent = (avatarName == currentAvatar);
// 设置选中状态
toggle.isOn = isCurrent;
// 【修改点】只要 isOn 为 true,就显示对号
// 这里的逻辑是:如果是当前用户装备的头像,打开面板时默认是选中的,且有对号
if (isCurrent)
{
if (checkMark != null) checkMark.gameObject.SetActive(true);
_pendingAvatarName = avatarName;
}
// 监听点击事件
toggle.onValueChanged.AddListener(isOn =>
{
// 【修改点】对号显示完全跟随 isOn 状态
// 当点击这个 Toggle 变成 true 时,显示对号;变成 false 时,隐藏对号
if (checkMark != null)
{
checkMark.gameObject.SetActive(isOn);
}
if (isOn)
{
_pendingAvatarName = avatarName;
// 实时更新预览大图
if (img_ShowAvatar != null)
{
img_ShowAvatar.sprite = sprite;
}
// 手动单选逻辑:关闭其他 Toggle
foreach (var t in _avatarToggles)
{
if (t == toggle) continue;
t.SetIsOnWithoutNotify(false);
// 【修改点】强制隐藏其他 Toggle 的对号
// 虽然上面 SetIsOnWithoutNotify(false) 会触发各自的 onValueChanged=false,
// 但为了保险起见,或者防止逻辑冲突,这里显式隐藏一次。
var otherMark = t.transform.childCount > 2 ? t.transform.GetChild(2) : null;
if (otherMark != null) otherMark.gameObject.SetActive(false);
}
}
});
}
}
}
/// <summary>
/// 点击头像项 → 更新主头像 + 上传到服务端
/// </summary>
private void ApplyAvatar(string avatarUrl)
/// <summary>点击“使用”按钮 → 确认数据,更新主头像</summary>
private void OnClickUseAvatar()
{
// 更新主头像显示
LoadAvatarImage(sprite_Avatar, avatarUrl);
if (string.IsNullOrEmpty(_pendingAvatarName))
{
Debug.Log("[UserInfoPanel] 未选中头像");
return;
}
// 统一交给 GameManager 处理(上传+缓存+事件)
gameManager.ApplyAvatar(avatarUrl);
// 1. 更新正式用户数据头像
LoadAvatarImage(sprite_Avatar, _pendingAvatarName);
// 2. 上传到服务器/更新本地缓存
gameManager.ApplyAvatar(_pendingAvatarName);
// 注意:这里不再需要遍历去更新对号了,因为对号在点击 Toggle 时已经跟着动了
// 点“使用”只是把当前的预览状态保存下来。
}
/// <summary>头像变更回调(网络返回后)</summary>
private void OnAvatarChanged(Sprite sprite)
{
if (sprite_Avatar != null && sprite != null)
sprite_Avatar.sprite = sprite;
if (img_ShowAvatar != null && sprite != null)
img_ShowAvatar.sprite = sprite;
}
// ==================== 工具 ====================