I’m using a UISlider to create a HealthBar with my own cool fill graphic rather than the default UISprite. While I’ll describe the problem I’m having doing it my way, if there’s a better way I’d be just as interested in hearing that as in hearing how to fix my way.
The general problem is that, with most graphics, the Fill gets stretched in awkward ways. The default UISprite works well because it has a really tight 9-slice configuration which is not suitable for most sprites, especially ones with rounded corners.
My current workaround is to replace the Fill Image with a RectMask2D, and then place my cool, rounded graphic as a child Image of the Fill object. As the slider value changes, the mask changes size, revealing the portion of the child image relative to the slider value. This works great, except for one thing, which is correctly sizing the child object.
I first tried setting the child Rect Anchor Presets to stretch to fill the parent, which is the Rect of the RectMask2D. This doesn’t work since the RectMask2D is changing its own Rect size.
I then found if I fixed the rect size and set the child Anchor Presets to middle left (for a health bar growing from left to right) that I got what I wanted…UNTIL…I changed display ratios
Since most of my UI elements are set to stretch to the panel they’re in, I now have a child element (the child fill image) that does not stretch and cannot be set to stretch. So it looks perfect when using the display ratio where the fixed size was initially set, but then it’s too narrow or too wide when switching to other display ratios. And that’s where I’m stuck.
While I could throw a script onto my child fill object to reset its own fixed size based on the display ratio, since custom health bars are so common, I figured there must be some way to use the default UISlider system to implement them across display ratios without resorting to custom scripts.
Your approach is good so far. Maybe you can play around with the Canvas Scaler, but most of the time the results are still not so good.
You may have noticed not only here that uGUI uses often constant sizes instead of relative sizes (e.g. font size). That is the reason why I created a tool called Better UI which helps solving such things.
Unfortunately the feature you describe (adjust the size delta according to resolution) is not present in the currently released version of Better UI. I already created it but it only works right now with the next, not yet released version of my asset.
I am not sure if I can make a version for you soon, because I need to clean up and test some code while I am involved in another project and will be on holidays soon.
So, right now the only way I see is to write something yourself.
PS: An alternative: use a sprite with the right aspect ratio with Image Type Filled.
Sorry for the double post, but I want to make sure that you notice my second answer…
I just realized that there is indeed another way to achieve your goal with help of a built in unity component.
You have to adjust the anchors of the image first: put it on the left but snapped to the upper and lower edge of the rect transform. I guess the height should be the same as the height of the parent.
Then add an Aspect Ratio Fitter to the image. Set it to “Height controls width”. The aspect ratio should be calculated from the current size.
If you then change the resolution, the height adjusts because of the anchors and the width adjusts because of the Aspect Ratio Fitter.
I think this should be the behaviour you want.
I was hoping it would be something easy like this, but I don’t think this will do the trick. Aspect Ratio Fitter doesn’t “fit” something to the aspect ratio, it “forces” that thing to a specified aspect ratio. So if you wanted a box to be 5 wide and 3 tall, using the AspectRatioFitter would make that box 5 x 3 whether your display ratio was portrait, or landscape or anything in between
In my case, I want a health bar that’s always 100 pixels tall and half the width of the screen, whether landscape, portrait, 4:3, etc… Since my width is dynamic, and my height is fixed, the aspect ratio of my fill will be different for any display ratio. The solution to that is usually stretch to parent rect, which is the problem when using a slider since the parent is also changing width dynamically
Thanks for the suggestion though
Maybe there’s a way for a child to anchor itself to its grandparent, and ignore the parent, which is all I’d need in this case
While I still hope there’s a standard component that I’m missing, here’s the hacky approach of adding a script to any RectTransfrom to set it to stretch to a Target RectTransfrom after all the display ratio resizing and stretching has taken place
To make it work, the RectTransform GameObject should not use one of the stretch anchor presets
using UnityEngine.UI;
public class RectStretchToTarget : MonoBehaviour {
public RectTransform Target;
void Start() {
StartCoroutine(CheckRectOneFrameLater());
}
private IEnumerator CheckRectOneFrameLater() {
yield return null;
//Two Approaches, an axis at a time
//this.GetComponent<RectTransform>().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal,Target.rect.width);
//this.GetComponent<RectTransform>().SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,Target.rect.height);
//or using sizeDelta
this.GetComponent<RectTransform>().sizeDelta = new Vector2 (Target.rect.width, Target.rect.height);
}
}