1. 新增多语言国家配置项,完善语言包 2. 实现国家选择弹窗组件,支持搜索、滚动定位和返回逻辑 3. 个人页面添加国家选择入口与展示逻辑 4. 排行榜列表新增国家名称展示 5. 优化数据变更检测逻辑,过滤无意义空值 6. 调整部分UI布局适配新增元素
251 lines
7.5 KiB
C#
251 lines
7.5 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using Kill.Managers;
|
||
using Kill.Network;
|
||
using Kill.UI;
|
||
|
||
public class SelectCountry : MonoBehaviour
|
||
{
|
||
public GameObject countryPrefab;
|
||
public Transform countryParent;
|
||
public Button submitButton;
|
||
public Button backButton;
|
||
public InputField searchInput;
|
||
public ScrollRect scrollRect;
|
||
LanguageManager.Country selectCountry;
|
||
private bool _hasSelection;
|
||
private string _originalCode;
|
||
/// <summary>
|
||
/// 未选中 选中
|
||
/// </summary>
|
||
public Color[] textColors;
|
||
|
||
private List<SelectCountryItem> _items = new List<SelectCountryItem>();
|
||
|
||
/// <summary>
|
||
/// 确认回调:code 为选中的国家代码,null 表示返回/取消
|
||
/// </summary>
|
||
public System.Action<string> onConfirm;
|
||
|
||
/// <summary>
|
||
/// 初始化
|
||
/// </summary>
|
||
/// <param name="code">当前选中的国家代码</param>
|
||
/// <param name="showBackButton">是否显示返回按钮(主页不显示)</param>
|
||
public void Init(string code, bool showBackButton = true)
|
||
{
|
||
_originalCode = code;
|
||
|
||
countryPrefab.SetActive(false);
|
||
// 清理旧 item
|
||
foreach (var item in _items)
|
||
Destroy(item.gameObject);
|
||
_items.Clear();
|
||
_hasSelection = false;
|
||
|
||
// 返回按钮
|
||
if (backButton != null)
|
||
{
|
||
backButton.gameObject.SetActive(showBackButton);
|
||
backButton.onClick.RemoveAllListeners();
|
||
backButton.onClick.AddListener(OnBack);
|
||
if (showBackButton)
|
||
UIManager.Instance.RegisterBackAction(OnBack);
|
||
}
|
||
|
||
if (LanguageManager.Instance == null || LanguageManager.Instance.countryList == null)
|
||
return;
|
||
|
||
foreach (var country in LanguageManager.Instance.countryList)
|
||
{
|
||
var go = Instantiate(countryPrefab, countryParent);
|
||
var item = go.AddComponent<SelectCountryItem>();
|
||
item.Init(this, country);
|
||
_items.Add(item);
|
||
item.gameObject.SetActive(true);
|
||
}
|
||
|
||
// 绑定搜索
|
||
if (searchInput != null)
|
||
{
|
||
searchInput.onValueChanged.RemoveAllListeners();
|
||
searchInput.onValueChanged.AddListener(OnSearchChanged);
|
||
}
|
||
|
||
// 设置默认选中(code 为空时不选中)
|
||
if (!string.IsNullOrEmpty(code))
|
||
SelectCountryByCode(code);
|
||
|
||
// 自动滚动到选中项
|
||
ScrollToSelected();
|
||
|
||
UpdateSubmitButton();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回按钮点击
|
||
/// </summary>
|
||
private void OnBack()
|
||
{
|
||
onConfirm?.Invoke(null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 滚动到当前选中的国家项(居中显示)
|
||
/// </summary>
|
||
private void ScrollToSelected()
|
||
{
|
||
if (scrollRect == null || !_hasSelection) return;
|
||
|
||
int index = _items.FindIndex(i => i.Country.code == selectCountry.code);
|
||
if (index < 0) return;
|
||
|
||
Canvas.ForceUpdateCanvases();
|
||
|
||
var itemRect = _items[index].GetComponent<RectTransform>();
|
||
float contentHeight = scrollRect.content.rect.height;
|
||
float viewportHeight = scrollRect.viewport.rect.height;
|
||
|
||
if (contentHeight <= viewportHeight) return;
|
||
|
||
// 计算目标滚动位置:使选中项居中
|
||
float maxScrollY = contentHeight - viewportHeight;
|
||
float itemCenterY = Mathf.Abs(itemRect.anchoredPosition.y) + itemRect.rect.height / 2;
|
||
float targetScrollY = itemCenterY - viewportHeight / 2;
|
||
targetScrollY = Mathf.Clamp(targetScrollY, 0, maxScrollY);
|
||
|
||
scrollRect.verticalNormalizedPosition = 1f - targetScrollY / maxScrollY;
|
||
}
|
||
|
||
private void OnSearchChanged(string keyword)
|
||
{
|
||
foreach (var item in _items)
|
||
{
|
||
item.gameObject.SetActive(item.MatchKeyword(keyword));
|
||
}
|
||
}
|
||
|
||
public void SelectCountryByCode(string code)
|
||
{
|
||
_hasSelection = !string.IsNullOrEmpty(code);
|
||
foreach (var item in _items)
|
||
{
|
||
bool isSelected = _hasSelection && item.Country.code == code;
|
||
item.SetSelected(isSelected);
|
||
if (isSelected)
|
||
selectCountry = item.Country;
|
||
}
|
||
UpdateSubmitButton();
|
||
}
|
||
|
||
public string GetSelectedCode()
|
||
{
|
||
return _hasSelection ? selectCountry.code : null;
|
||
}
|
||
|
||
private void UpdateSubmitButton()
|
||
{
|
||
if (submitButton != null)
|
||
{
|
||
submitButton.gameObject.SetActive(_hasSelection);
|
||
submitButton.onClick.RemoveAllListeners();
|
||
submitButton.onClick.AddListener(OnSubmit);
|
||
}
|
||
}
|
||
|
||
private async void OnSubmit()
|
||
{
|
||
if (!_hasSelection) return;
|
||
await UpdateCountryCodeAsync(selectCountry.code);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新用户国家代码
|
||
/// </summary>
|
||
private async System.Threading.Tasks.Task UpdateCountryCodeAsync(string code)
|
||
{
|
||
try
|
||
{
|
||
var requestData = new CountryCodeRequest
|
||
{
|
||
country_code = code
|
||
};
|
||
|
||
var response = await NetworkCtrl.Instance.Put<NoDataResponse>("/api/v1/user/country-code", requestData);
|
||
|
||
ResponseCodeHandler.HandleResponse(response,
|
||
onSuccess: (data) =>
|
||
{
|
||
if (DataManager.Instance.userInfo != null)
|
||
DataManager.Instance.userInfo.country_code = code;
|
||
onConfirm?.Invoke(code);
|
||
},
|
||
onError: null
|
||
);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"更新国家代码失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
internal class SelectCountryItem : MonoBehaviour
|
||
{
|
||
public LanguageManager.Country Country { get; private set; }
|
||
private SelectCountry _parent;
|
||
private Text _nameText;
|
||
private GameObject _selectGo;
|
||
private Color _selectedColor;
|
||
private Color _unselectedColor;
|
||
|
||
public void Init(SelectCountry parent, LanguageManager.Country country)
|
||
{
|
||
_parent = parent;
|
||
Country = country;
|
||
|
||
_nameText = transform.Find("name")?.GetComponent<Text>();
|
||
_selectGo = transform.Find("选中")?.gameObject;
|
||
|
||
_selectedColor = parent.textColors.Length > 0 ? parent.textColors[0] : Color.white;
|
||
_unselectedColor = parent.textColors.Length > 1 ? parent.textColors[1] : Color.gray;
|
||
|
||
// 显示国家名称(根据当前语言)
|
||
bool isChinese = LanguageManager.Instance != null && LanguageManager.Instance.languageType == LanguageManager.LanguageType.Chinese;
|
||
if (_nameText != null)
|
||
_nameText.text = isChinese ? country.name_zh : country.name_en;
|
||
|
||
// 点击事件
|
||
var btn = GetComponent<Button>();
|
||
if (btn == null)
|
||
btn = gameObject.AddComponent<Button>();
|
||
btn.onClick.AddListener(OnClick);
|
||
}
|
||
|
||
public void SetSelected(bool selected)
|
||
{
|
||
if (_nameText != null)
|
||
_nameText.color = selected ? _selectedColor : _unselectedColor;
|
||
if (_selectGo != null)
|
||
_selectGo.SetActive(selected);
|
||
}
|
||
|
||
public bool MatchKeyword(string keyword)
|
||
{
|
||
if (string.IsNullOrEmpty(keyword))
|
||
return true;
|
||
var k = keyword.ToLower();
|
||
return Country.name_zh.ToLower().Contains(k)
|
||
|| Country.name_en.ToLower().Contains(k)
|
||
|| Country.code.ToLower().Contains(k);
|
||
}
|
||
|
||
private void OnClick()
|
||
{
|
||
_parent.SelectCountryByCode(Country.code);
|
||
}
|
||
}
|