public virtual bool Raycast(Vector2 sp, Camera eventCamera) { if (!isActiveAndEnabled) { return(false); } var t = transform; var components = ListPool <Component> .Get(); bool ignoreParentGroups = false; bool continueTraversal = true; while (t != null) { t.GetComponents(components); for (var i = 0; i < components.Count; i++) { var canvas = components[i] as Canvas; // 如果挂载了canvas组件,并且overrideSorting为true,这个一般是嵌套的canvas if (canvas != null && canvas.overrideSorting) { continueTraversal = false; } // 实现ICanvasRaycastFilter接口的组件,CanvasGroup也实现了此接口 var filter = components[i] as ICanvasRaycastFilter; if (filter == null) { continue; } var raycastValid = true; var group = components[i] as CanvasGroup; // 这里有坑,检测完子节点再检测父节点,父节点IsRaycastLocationValid完全有可能返回false if (group != null) { // 勾选了ignoreParentGroups,那么只有这层的canvasGroup会进行检测 if (ignoreParentGroups == false && group.ignoreParentGroups) { ignoreParentGroups = true; raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } else if (!ignoreParentGroups) { raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } } else { // 调用IsRaycastLocationValid方法 raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } if (!raycastValid) { ListPool <Component> .Release(components); return(false); } } t = continueTraversal ? t.parent : null; } ListPool <Component> .Release(components); return(true); }
/// <summary> /// When a GraphicRaycaster is raycasting into the scene it does two things. First it filters the elements using their RectTransform rect. Then it uses this Raycast function to determine the elements hit by the raycast. /// </summary> /// <param name="sp">Screen point being tested</param> /// <param name="eventCamera">Camera that is being used for the testing.</param> /// <returns>True if the provided point is a valid location for GraphicRaycaster raycasts.</returns> public virtual bool Raycast(Vector2 sp, Camera eventCamera) { if (!isActiveAndEnabled) { return(false); } var t = transform; var components = ListPool <Component> .Get(); bool ignoreParentGroups = false; bool continueTraversal = true; while (t != null) { t.GetComponents(components); for (var i = 0; i < components.Count; i++) { var canvas = components[i] as Canvas; if (canvas != null && canvas.overrideSorting) { continueTraversal = false; } var filter = components[i] as ICanvasRaycastFilter; if (filter == null) { continue; } var raycastValid = true; var group = components[i] as CanvasGroup; if (group != null) { if (ignoreParentGroups == false && group.ignoreParentGroups) { ignoreParentGroups = true; raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } else if (!ignoreParentGroups) { raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } } else { raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } if (!raycastValid) { ListPool <Component> .Release(components); return(false); } } t = continueTraversal ? t.parent : null; } ListPool <Component> .Release(components); return(true); }
/// <summary> /// Show the dropdown. /// /// Plan for dropdown scrolling to ensure dropdown is contained within screen. /// /// We assume the Canvas is the screen that the dropdown must be kept inside. /// This is always valid for screen space canvas modes. /// For world space canvases we don't know how it's used, but it could be e.g. for an in-game monitor. /// We consider it a fair constraint that the canvas must be big enough to contain dropdowns. /// </summary> public void Show() { if (!IsActive() || !IsInteractable() || m_Dropdown != null) { return; } // Get root Canvas. var list = ListPool <Canvas> .Get(); gameObject.GetComponentsInParent(false, list); if (list.Count == 0) { return; } // case 1064466 rootCanvas should be last element returned by GetComponentsInParent() var listCount = list.Count; Canvas rootCanvas = list[listCount - 1]; for (int i = 0; i < listCount; i++) { if (list[i].isRootCanvas || list[i].overrideSorting) { rootCanvas = list[i]; break; } } ListPool <Canvas> .Release(list); if (!validTemplate) { SetupTemplate(rootCanvas); if (!validTemplate) { return; } } m_Template.gameObject.SetActive(true); // Instantiate the drop-down template m_Dropdown = CreateDropdownList(m_Template.gameObject); m_Dropdown.name = "Dropdown List"; m_Dropdown.SetActive(true); // Make drop-down RectTransform have same values as original. RectTransform dropdownRectTransform = m_Dropdown.transform as RectTransform; dropdownRectTransform.SetParent(m_Template.transform.parent, false); // Instantiate the drop-down list items // Find the dropdown item and disable it. DropdownItem itemTemplate = m_Dropdown.GetComponentInChildren <DropdownItem>(); GameObject content = itemTemplate.rectTransform.parent.gameObject; RectTransform contentRectTransform = content.transform as RectTransform; itemTemplate.rectTransform.gameObject.SetActive(true); // Get the rects of the dropdown and item Rect dropdownContentRect = contentRectTransform.rect; Rect itemTemplateRect = itemTemplate.rectTransform.rect; // Calculate the visual offset between the item's edges and the background's edges Vector2 offsetMin = itemTemplateRect.min - dropdownContentRect.min + (Vector2)itemTemplate.rectTransform.localPosition; Vector2 offsetMax = itemTemplateRect.max - dropdownContentRect.max + (Vector2)itemTemplate.rectTransform.localPosition; Vector2 itemSize = itemTemplateRect.size; m_Items.Clear(); Toggle prev = null; var optionsCount = options.Count; for (int i = 0; i < optionsCount; ++i) { OptionData data = options[i]; DropdownItem item = AddItem(data, value == i, itemTemplate, m_Items); if (item == null) { continue; } // Automatically set up a toggle state change listener item.toggle.isOn = value == i; item.toggle.onValueChanged.AddListener(x => OnSelectItem(item.toggle)); // Select current option if (item.toggle.isOn) { item.toggle.Select(); } // Automatically set up explicit navigation if (prev != null) { Navigation prevNav = prev.navigation; Navigation toggleNav = item.toggle.navigation; prevNav.mode = Navigation.Mode.Explicit; toggleNav.mode = Navigation.Mode.Explicit; prevNav.selectOnDown = item.toggle; prevNav.selectOnRight = item.toggle; toggleNav.selectOnLeft = prev; toggleNav.selectOnUp = prev; prev.navigation = prevNav; item.toggle.navigation = toggleNav; } prev = item.toggle; } // Reposition all items now that all of them have been added Vector2 sizeDelta = contentRectTransform.sizeDelta; sizeDelta.y = itemSize.y * m_Items.Count + offsetMin.y - offsetMax.y; contentRectTransform.sizeDelta = sizeDelta; float extraSpace = dropdownRectTransform.rect.height - contentRectTransform.rect.height; if (extraSpace > 0) { dropdownRectTransform.sizeDelta = new Vector2(dropdownRectTransform.sizeDelta.x, dropdownRectTransform.sizeDelta.y - extraSpace); } // Invert anchoring and position if dropdown is partially or fully outside of canvas rect. // Typically this will have the effect of placing the dropdown above the button instead of below, // but it works as inversion regardless of initial setup. Vector3[] corners = new Vector3[4]; dropdownRectTransform.GetWorldCorners(corners); RectTransform rootCanvasRectTransform = rootCanvas.transform as RectTransform; Rect rootCanvasRect = rootCanvasRectTransform.rect; for (int axis = 0; axis < 2; axis++) { bool outside = false; for (int i = 0; i < 4; i++) { Vector3 corner = rootCanvasRectTransform.InverseTransformPoint(corners[i]); if ((corner[axis] < rootCanvasRect.min[axis] && !Mathf.Approximately(corner[axis], rootCanvasRect.min[axis])) || (corner[axis] > rootCanvasRect.max[axis] && !Mathf.Approximately(corner[axis], rootCanvasRect.max[axis]))) { outside = true; break; } } if (outside) { RectTransformUtility.FlipLayoutOnAxis(dropdownRectTransform, axis, false, false); } } var itemsCount = m_Items.Count; for (int i = 0; i < itemsCount; i++) { RectTransform itemRect = m_Items[i].rectTransform; itemRect.anchorMin = new Vector2(itemRect.anchorMin.x, 0); itemRect.anchorMax = new Vector2(itemRect.anchorMax.x, 0); itemRect.anchoredPosition = new Vector2(itemRect.anchoredPosition.x, offsetMin.y + itemSize.y * (itemsCount - 1 - i) + itemSize.y * itemRect.pivot.y); itemRect.sizeDelta = new Vector2(itemRect.sizeDelta.x, itemSize.y); } // Fade in the popup AlphaFadeList(m_AlphaFadeSpeed, 0f, 1f); // Make drop-down template and item template inactive m_Template.gameObject.SetActive(false); itemTemplate.gameObject.SetActive(false); m_Blocker = CreateBlocker(rootCanvas); }
public virtual bool Raycast(Vector2 sp, Camera eventCamera) { bool result; if (!base.isActiveAndEnabled) { result = false; } else { Transform transform = base.transform; List <Component> list = ListPool <Component> .Get(); bool flag = false; bool flag2 = true; while (transform != null) { transform.GetComponents <Component>(list); for (int i = 0; i < list.Count; i++) { Canvas canvas = list[i] as Canvas; if (canvas != null && canvas.overrideSorting) { flag2 = false; } ICanvasRaycastFilter canvasRaycastFilter = list[i] as ICanvasRaycastFilter; if (canvasRaycastFilter != null) { bool flag3 = true; CanvasGroup canvasGroup = list[i] as CanvasGroup; if (canvasGroup != null) { if (!flag && canvasGroup.ignoreParentGroups) { flag = true; flag3 = canvasRaycastFilter.IsRaycastLocationValid(sp, eventCamera); } else if (!flag) { flag3 = canvasRaycastFilter.IsRaycastLocationValid(sp, eventCamera); } } else { flag3 = canvasRaycastFilter.IsRaycastLocationValid(sp, eventCamera); } if (!flag3) { ListPool <Component> .Release(list); result = false; return(result); } } } transform = ((!flag2) ? null : transform.parent); } ListPool <Component> .Release(list); result = true; } return(result); }