源码9:DropDown
DropDwon 主要就是为了实现下拉选择的功能
public class Dropdown : Selectable, IPointerClickHandler, ISubmitHandler, ICancelHandler
{
...
protected internal class DropdownItem : MonoBehaviour, IPointerEnterHandler, ICancelHandler
{
//Item显示的文字
[SerializeField]
private Text m_Text;
//Item显示的底图
[SerializeField]
private Image m_Image;
//item的rectTransfom
[SerializeField]
private RectTransform m_RectTransform;
//可点击的Toggle
[SerializeField]
private Toggle m_Toggle;
...
}
...
}
Dropdown 继承自Selectable,同时继承IPointerClickHandler, ISubmitHandler ICancelHandler 三个接口。
内板包含一个DropdownItem类 继承自MonoBehaviour和IPointerEnterHandler, ICancelHandler两个接口。
DropdownItem 就是我们点击的时候出现的下拉框选项
DropdownItem 实现了IPointerEnterHandler 和 OnCancel
public virtual void OnPointerEnter(PointerEventData eventData)
{
EventSystem.current.SetSelectedGameObject(gameObject);
}
public virtual void OnCancel(BaseEventData eventData)
{
Dropdown dropdown = GetComponentInParent<Dropdown>();
if (dropdown)
dropdown.Hide();
}
当鼠标划入的时候 调用EventSystem的SetSelectedGameObject将本对象设置为选中的对象,表现就是Item对象的背景颜色变了。
当按键取消的时候 会调用dropdown的Hide 隐藏下拉列表
[SerializeField]
private int m_Value;
[SerializeField]
private OptionDataList m_Options = new OptionDataList();
DropDwon中m_Value 是记录选中的m_Options里的值对应的索引Index
m_Value 是个属性设置值的时候会调用Set方法
void Set(int value, bool sendCallback = true)
{
if (Application.isPlaying && (value == m_Value || options.Count == 0))
return;
m_Value = Mathf.Clamp(value, 0, options.Count - 1);
RefreshShownValue();
if (sendCallback)
{
// Notify all listeners
UISystemProfilerApi.AddMarker("Dropdown.value", this);
m_OnValueChanged.Invoke(m_Value);
}
}
public void RefreshShownValue()
{
OptionData data = s_NoOptionData;
if (options.Count > 0)
data = options[Mathf.Clamp(m_Value, 0, options.Count - 1)];
if (m_CaptionText)
{
if (data != null && data.text != null)
m_CaptionText.text = data.text;
else
m_CaptionText.text = "";
}
if (m_CaptionImage)
{
if (data != null)
m_CaptionImage.sprite = data.image;
else
m_CaptionImage.sprite = null;
m_CaptionImage.enabled = (m_CaptionImage.sprite != null);
}
当设置m_value的时候会调用RefreshShownValue 方法 并且发送m_OnValueChanged事件
RefreshShownValue 主要是刷新DropDown的显示 取出当前m_value对应的值的(图片 和 Text)设置到DropDown中
当点击的时候会调用OnPointerClick 进行列表的显示Show (OnSubmit 调用的也是一样)
public virtual void OnPointerClick(PointerEventData eventData)
{
Show();
}
Show的代码比较长 就不贴了 主要操作如下
- 调用SetupTemplate方法,设置模板。为Item添加DropdownItem,为m_Template添加Canvas,设置overrideSorting为true,sortingOrder为30000,为选项表尽可能的显示在前面,然后添加GraphicRaycaster,CanvasGroup组件,为了接受鼠标事件。
- CreateDropdownList,实例化DropDown实例,SetParent设置父节点
- 获得DropdownItem,以DropdownItem为模板创建Item,并填充数据。设置toggle状态,添加toggle的onValueChanged事件。
- 根据Item的数量设置Content的尺寸,Content是ScrollRect里的内容对象。并且如果DropDownList的高度大于Content的高度,便修正他的高度与Content相同。
- 然后判断DropDownList的四个角,是否超出了rootCanvas(Dropdown最上层的Canvas)的边界,便翻转DropDownList(DropDownList的四个角超出了rootCanvas的最小值,便往上弹出,否则往下弹出),然后设置Item的位置和尺寸。
- 通过调整CanvasGroup的alpha值,渐变显示Dropdown List,并将m_Template和itemTemplate设置为无效的。
- 调用CreateBlocker创建Blocker。Blocker在rootCanvas下一级,尺寸与rootCanvas相同,sortingOrder比Dropdown List的小1(29999)。添加了Image组件,颜色为全透明,添加了Button组件,添加了onClick的监听,回调Hide方法。由此我们可知道Blocker是用于阻挡住鼠标事件,即Dropdown List显示时,点击选项表以外的区域,都只是隐藏选项表,不会触发其他的组件。
- Hide方法,Alpha渐变隐藏Dropdown List,并在渐变结束后Destroy所有的Item和Dropdown List。接着DestroyBlocker。最后设置本对象为Select(高亮状态)。
Dropdown重写了Start方法,新建了一个FloatTween类型的TweenRunner变量m_AlphaTweenRunner并初始化,这个变量在显示/隐藏选项表(Dropdown List)的时候执行透明度渐变效果。
protected override void Start()
{
m_AlphaTweenRunner = new TweenRunner<FloatTween>();
m_AlphaTweenRunner.Init(this);
base.Start();
RefreshShownValue();
}
private void AlphaFadeList(float duration, float start, float end)
{
if (end.Equals(start))
return;
FloatTween tween = new FloatTween {duration = duration, startValue = start, targetValue = end};
tween.AddOnChangedCallback(SetAlpha);
tween.ignoreTimeScale = true;
m_AlphaTweenRunner.StartTween(tween);
}