Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How do you get the parent canvas?

Discussion in 'UGUI & TextMesh Pro' started by yoonitee, Mar 16, 2015.

  1. yoonitee

    yoonitee

    Joined:
    Jun 27, 2013
    Posts:
    2,363
    Is there a simple way to get the parent canvas of a UI element?

    Because for functions like:


    Code (CSharp):
    1.         RectTransformUtility.ScreenPointToLocalPointInRectangle(colorpad.rectTransform,Input.mousePosition,Camera.main,out localPoint);
    2.  

    you need to know whether the canvas is in Overlay mode or Camera mode. In order to either put Camera.main or null in the field.

    Or am I missing something? I don't want to put a public variable Canvas because I am making a prefab that can be dropped onto a canvas so it has to be defined only in the script.

    Or is there a way of using RectTransformUtility.ScreenPointToLocalPointInRectangle without having to get a reference to the canvas object to see what mode it is in. Really I'd like something like Input.camera to tell you how to interpret Input.mousePosition.

    At the moment I'm using this recursive function:

    Code (CSharp):
    1.     void getCanvas(GameObject g){
    2.         if(g.GetComponent<Canvas>()!=null) {
    3.             canvas=g.GetComponent<Canvas>();
    4.             return;
    5.         }else{
    6.             if(g.transform.parent!=null){
    7.                 getCanvas (g.transform.parent.gameObject);
    8.             }
    9.         }
    10.     }
     
    Last edited: Mar 16, 2015
  2. mh114

    mh114

    Joined:
    Nov 17, 2013
    Posts:
    294
    Have you considered GetComponentInParent<Canvas>() to replace your recursive lookup?
     
  3. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,685
    Beat me to it @mh114
    This is exactly how to do it.
    You can combine it with the tests above (parent == null) if you want the top most parent canvas, remembering that Canvases can be nested.

    If you have many Canvases, consider tagging them and using "GameObject.FindGameObjectWithTag("CanvasName");"
     
    Ruhan-Bello, Astrokatz and Phobarp like this.
  4. yoonitee

    yoonitee

    Joined:
    Jun 27, 2013
    Posts:
    2,363
    Ah. That sounds much simpler! Thanks.
     
  5. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,996
    GetComponentsInParents is recursive so topmost canvas is
    Code (CSharp):
    1. Canvas[] c = GetComponentsInParents<Canvas>();
    2. Canvas topmost = c[c.Length-1];
     
  6. StaffanEk

    StaffanEk

    Joined:
    Jul 13, 2012
    Posts:
    380
    Did you make that up? Or has there actually been a GetComponentsInParents in the past?
     
  7. Harinezumi

    Harinezumi

    Joined:
    Jan 7, 2013
    Posts:
    54
    There is a typo in the function name, it is GetComponentsInParent(), not *Parents, but it exists at least since Unity 4.5. So along the lines of laurentlavigne:

    Code (CSharp):
    1. public static Canvas GetTopmostCanvas(Component component) {
    2.     Canvas[] parentCanvases = component.GetComponentsInParent<Canvas>();
    3.     if (parentCanvases != null && parentCanvases.Length > 0) {
    4.         return parentCanvases[parentCanvases.Length - 1];
    5.     }
    6.     return null;
    7. }
     
    Last edited: Feb 2, 2017
    Thorny2000 likes this.
  8. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,146
    Depending on your layout, if the canvas is the top parent you should be able to do

    Code (CSharp):
    1. transform.root.GetComponent<Canvas>();
    I'm pretty sure I used this somewhere for something.
     
  9. Harinezumi

    Harinezumi

    Joined:
    Jan 7, 2013
    Posts:
    54
    So maybe you could do this then:
    Good idea! In case it were not the top one, you can do:
    Code (CSharp):
    1. Canvas topmostCanvas = transform.root.GetComponentInChildren<Canvas>();
    The only problem is that if there are branches in the hierarchy and different branches have Canvases, it might not be the Canvas of your transform.
     
  10. o0_ChromiumGames_0o

    o0_ChromiumGames_0o

    Joined:
    Mar 28, 2017
    Posts:
    1
    I think this is the cleanest and the most reusable way. There was just a tiny syntax issue;).

    Code (CSharp):
    1. Canvas[] c = GetComponentsInParent<Canvas>();
    2. Canvas topMostCanvas = c[c.Length - 1];
     
    laurentlavigne likes this.
  11. Bodix_

    Bodix_

    Joined:
    May 6, 2018
    Posts:
    15
    What about this:
    Code (CSharp):
    1. private static Canvas GetRootCanvas(this RectTransform rectTransform)
    2. {
    3.     Canvas canvas = rectTransform.GetComponentInParent<Canvas>();
    4.  
    5.     if (canvas)
    6.         return canvas.isRootCanvas ? canvas : canvas.rootCanvas;
    7.     else
    8.         return null;
    9. }
    Not the better option (because it also iterates over all hierarchy), but it may be useful for someone.
     
    Last edited: Mar 22, 2021
    ilievant and andrew_pearce_ like this.