- Home /
Is there a way to move a UI mask without moving child content?
I'd like to transform the masked area without transforming the content being masked, like moving a window over a static object. AFAIK masked content must be on a child GameObject of the mask GameObject right now, so transforms propagate down the hierarchy. It seems I'd prefer it to be set up so a mask takes an explicit reference to a content GameObject, rather than inferring the mask / content relationship through hierarchy. This would allow more flexibility, as you could still have the parent-child relationship if you so wish.
Answer by Mmmpies · Mar 08, 2015 at 01:28 PM
This isn't far off, I just modified a drag script I already had to maintain the child position.
Put this script on the Mask panel and drag the parent canvas onto the ParentRT slot, the Mask panel onto MyRect and the child Image onto the MyChild slot:
private bool mouseDown = false;
private Vector3 startMousePos;
private Vector3 startPos;
private bool restrictX;
private bool restrictY;
private float fakeX;
private float fakeY;
private float myWidth;
private float myHeight;
private bool snapHome = true;
public RectTransform ParentRT;
public RectTransform MyRect;
public RectTransform MyChild;
private Vector3 ChildPos;
void Start()
{
myWidth = (MyRect.rect.width + 5) / 2;
myHeight = (MyRect.rect.height + 5) / 2;
ChildPos = MyChild.transform.position;
}
public void OnPointerDown(PointerEventData ped)
{
mouseDown = true;
startPos = transform.position;
startMousePos = Input.mousePosition;
}
public void OnPointerUp(PointerEventData ped)
{
mouseDown = false;
if(snapHome)
transform.position = startPos;
}
void Update ()
{
if (mouseDown) {
Vector3 currentPos = Input.mousePosition;
Vector3 diff = currentPos - startMousePos;
Vector3 pos = startPos + diff;
transform.position = pos;
MyChild.transform.position = ChildPos;
if(transform.localPosition.x < 0 - ((ParentRT.rect.width / 2) - myWidth) || transform.localPosition.x > ((ParentRT.rect.width / 2) - myWidth))
restrictX = true;
else
restrictX = false;
if(transform.localPosition.y < 0 - ((ParentRT.rect.height / 2) - myHeight) || transform.localPosition.y > ((ParentRT.rect.height / 2) - myHeight))
restrictY = true;
else
restrictY = false;
if(restrictX)
{
if(transform.localPosition.x < 0)
fakeX = 0 - (ParentRT.rect.width / 2) + myWidth;
else
fakeX = (ParentRT.rect.width / 2) - myWidth;
Vector3 xpos = new Vector3 (fakeX, transform.localPosition.y, 0.0f);
transform.localPosition = xpos;
}
if(restrictY)
{
if(transform.localPosition.y < 0)
fakeY = 0 - (ParentRT.rect.height / 2) + myHeight;
else
fakeY = (ParentRT.rect.height / 2) - myHeight;
Vector3 ypos = new Vector3 (transform.localPosition.x, fakeY, 0.0f);
transform.localPosition = ypos;
}
}
}
}
EDIT
Just a heads up I'm not getting mail notifications so very limitied to how I can use Answers ATM, if you post a comment I won't be notified. I'm not ignoring you, just not getting notification!
@$$anonymous$$mmpies I propose a simpler solution below but it's not as performance efficient as you solution. If you had the chance to use the simpler solution in the past and profile it, let us know :)
Answer by tgouala-wellfiredLtd · Aug 09, 2018 at 04:00 AM
There is a very simple way tested in Unity 2018.2.
Be aware that this solution changes UI hierarchy which may be less efficient than the first solution proposed. In my case I needed it on a desktop project and it was totally fine. Better you profile it (especially mobile users).
Before to change the position of the mask, simply
Set the parent of the masked child to null.
Move the mask.
Assign back the child.
Here an example code inside a tween :
DOTween.To(() => MaskPosition, value => MaskPosition = value,
destination, duration);
private Vector2 MaskPosition
{
get { return _mask.rectTransform.anchoredPosition; }
set
{
_child.parent = null;
_mask.rectTransform.anchoredPosition = value;
_child.parent = _mask.rectTransform;
}
}
Answer by tayl0r · Jul 15, 2017 at 12:10 AM
You can actually do masking without using direct ancestors. Setup your hierarchy like so:
- left mask (Image)
- right mask (Image)
- mask parent (Image + Mask + this object should be 0 size because you dont actually want its mask to be applied)
- child object that gets masked
- child object that gets masked
- child object that gets masked
Once you set it up like that, you have to go into 1 of your child objects and toggle the rendering component on and off to refresh the masking setup.
Tested in Unity 5.2.2p4
can you elaborate on this please? How do you apply left and right masks to the content that is supposed to be masked?
Thanks
Hi, it actually only works in 5.2. In 5.3 this doesn't seem to work anymore.
But, you can still do it, you just have to write your own shaders that use the stencil buffer.
ok. I ended up using this LockUIItem script.
Your answer
Follow this Question
Related Questions
{Android} {Unity 5.3.1f1} The UI Mask Component is pissing me off... 1 Answer
Aliasing When Using UI Mask 3 Answers
How to solve UI pixel problem 0 Answers
Override sorting not working? The canvas just freezes………zzzzz 0 Answers
Dropdown inside mask 1 Answer