- Home /
4.6 UI ScrollBar force handle size to be fixed
Using the new UI with a ScrollBar is there a way to respect the aspect ratio / size of the handle?
If I use an image that I want to stay the same size, or at least scale with the UI on resolution change, but not shrink and grow to fill the slider area if the content of the scroll panel changes.
What I'm trying to do is use an image for the handle but that image doesn't scale well, quite happy for the button to have to travel the full length of the bar just to move the content slightly if that happens.
Even happy to have a wrapper script that uses a transparent ScrollBar and sends the value to it based on a value 0 to 1 depending on the size of a panel it sits on and the hadles position. Which is what I'm going to script if I can't find a better solution.
Answer by tkoknordic · Jan 28, 2015 at 05:20 PM
Hi,
I have a super small solution:
Put the Scroll bar object in ScrollRect OnValueChanged event and then select there Scrollbar.size and set the atribute to 0:
Then you still need to set the scrollbar.size to 0 at the start of your game. I did a small script for that:
public class FakeScrollBar : MonoBehaviour {
void Awake() {
transform.GetComponent<Scrollbar>().size = 0;
}
}
That's a great solution but I cant see Scrollbar.size what version are you on or is it a Pro feature?
$$anonymous$$mmpies, It's not a function but a field and you have it there in your picture where you can see the "float size".
Cheers @tkoknordic, that'll be my dyslexic eyes then :¬)
Good of you to take the time to post it.
Answer by casimps1 · Jun 21, 2015 at 04:39 PM
The answer is that you shouldn't be using a scrollbar. As far as Unity is concerned, that scaling is by definition part of Scrollbar behavior.
What you want is to use their Slider widget instead.
This doesn't work in conjunction with a ScrollRect, though.
This is the correct answer, at least for me. All you need to do is to add this script to your slider.
public class ScrollPosition : $$anonymous$$onoBehaviour {
public Slider slider;
public ScrollRect scrollRect;
// Use this for initialization
public void ChangeScrollPos()
{
scrollRect.horizontalNormalizedPosition = slider.value;
}
}
And use ChangeScrollPos() function in your sliders OnValueChanged. This is exactly what i did in my game Colors
Your code does not support changing the slider position by moving the scroll rect directly by swiping. I modified your code a little to make it work both ways.
public class VerticalSliderScrollPosition : MonoBehaviour {
[SerializeField] private Slider slider;
[SerializeField] private ScrollRect scrollRect;
private void Awake() {
slider.onValueChanged.AddListener(ChangeScrollPos);
scrollRect.onValueChanged.AddListener(ChangeSliderPos);
}
public void ChangeScrollPos(float value) {
scrollRect.verticalNormalizedPosition = value;
}
public void ChangeSliderPos(Vector2 vector) {
slider.value = vector.y;
}
}
No need to use OnValueChanged from inspector with this code.
Answer by immeasurability · Nov 17, 2016 at 11:39 AM
replace base class of sroll rect
using UnityEngine.UI;
public class ScrollRect_fix : ScrollRect {
override protected void LateUpdate() {
base.LateUpdate();
if (this.horizontalScrollbar) {
this.horizontalScrollbar.size=0;
}
}
override public void Rebuild(CanvasUpdate executing) {
base.Rebuild(executing);
if (this.horizontalScrollbar) {
this.horizontalScrollbar.size=0;
}
}
}
@tkoknordic 's answer not really working decently. This, on the other hand, works like a charm!
Would propose an edit here. Use this modified version, and you can bypass all scrollbar resizing altogether.
using UnityEngine.UI;
public class ScrollRect_fix : ScrollRect
{
private float verticalScrollbarHandlerSize;
private float horizontalScrollbarHandlerSize;
override protected void LateUpdate()
{
if (this.horizontalScrollbar)
horizontalScrollbarHandlerSize = this.horizontalScrollbar.size;
if (this.verticalScrollbar)
verticalScrollbarHandlerSize = this.verticalScrollbar.size;
base.LateUpdate();
if (this.horizontalScrollbar)
this.horizontalScrollbar.size = horizontalScrollbarHandlerSize;
if (this.verticalScrollbar)
this.verticalScrollbar.size = verticalScrollbarHandlerSize;
}
override public void Rebuild(CanvasUpdate executing)
{
if (this.horizontalScrollbar)
horizontalScrollbarHandlerSize = this.horizontalScrollbar.size;
if (this.verticalScrollbar)
verticalScrollbarHandlerSize = this.verticalScrollbar.size;
base.Rebuild(executing);
if (this.horizontalScrollbar)
this.horizontalScrollbar.size = horizontalScrollbarHandlerSize;
if (this.verticalScrollbar)
this.verticalScrollbar.size = verticalScrollbarHandlerSize;
}
}
@immeasurability None of the above solutions is working properly but yours does. Thank you - 2018.
@$$anonymous$$earjade I tried your edit and it works perfeclty! Almost... there is this thing that Value changes from 0 to 1 and from 1 to 0 when there is no content. I don't know what causing it, but in Console I have warning: "Send$$anonymous$$essage cannot be called during Awake, CheckConsistency, or OnValidate"
Answer by zXcongducXz · Jul 31, 2015 at 08:44 AM
In Scroll Rect (Script) Component
Set Movement Type = Clamped
On Value Changed (Single) add new, Drag Scrollbar (Script), Set Scrollbar\float size, set value = 0
$$anonymous$$ake sure you set it in ScrollRect not in ScrollBar, otherwise it would produce glitches.
The initial value is not quite right, the handle still expands. Then when you drag it, it snaps back to the fixed size.
Answer by Mmmpies · Jan 18, 2015 at 03:55 PM
OK got it sorted but it's messy.
Left a real scrollbar with a CanvasGroup on it and set Alpha to 0, untick Interactable and Blocksraycast and tick Ignore Parent Group.
Set the Scroll Rect script to use this ScrollBar.
Then put a Slider on the scene and fill in with whatever images you want to use. This is visible but I put a CanvasGroup on it so I can vanish it if the ScrollBar.size < 0.99f.
Then added this script onto it:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class FakeScrollBar : MonoBehaviour {
public Scrollbar RealScrollBar;
public void PassThrough(float scrollValue)
{
//Debug.Log (scrollValue);
RealScrollBar.value = scrollValue;
}
}
Dragged the script onto the Slider and drag the invisible ScrollBar onto the public ScrollBar slot in the script.
Click + in the Sliders OnValueChanged and drag the Slider with the script onto the new slot that appears. From the dropdown select FakeScrollBar -> PassThrough.
It works but still interested if anyone has a better idea.
EDIT
What a massive idiot, RTFM @Mmmpies RTFM!
OK delete the hidden ScrollBar and change the the script to this:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class FakeScrollBar : MonoBehaviour {
public ScrollRect MyScrollRect;
public void PassThrough(float scrollValue)
{
MyScrollRect.verticalNormalizedPosition = scrollValue;
}
}
if working in the horizontal change the verticalNormaizedPosition to horizontalNormalizedPosition and a Slider now works as a ScrollBar, just drag the ScrollRect onto the public slot in the script.
Ah the benefits of a nights sleep and a really nice cup of tea.
Than your edit worked like a charm but where is that parameter of float scrollValue co$$anonymous$$g from