Unity: add different scroll speeds in UI Scroll Rect - unity3d

In Unity, I created a UI Scroll Rect Object. This object has two children, a Button Handler with different Buttons, and a Background.
Using it, both the Buttons and the Background are scrolling at the same speed. I want the Buttons to scroll faster than the Background, thus creating an effect of depth to the scrolling.
I can not find any options in the Objects or the Scroll Rect for this. Any ideas?

This will require a tiny bit of scripting. The best way in my opinion would involve following steps:
a) for each button, add a component that remembers its start position.
b) grab a scrollrect instance in parent
c) using it to grab an instance of ScrollBar
d) scrollbars have onValueChanged(float) callbacks, you can bind to, to know when the scroll position changes (to avoid doing checks in Update)
e) every time a scrollbar has moved (This will work regardless of whether the user used the scrollbar, or used another mean of scrolling, as the scrollrect will move the scrollbar, which will fire the event anyways), you get a callback with current scrollbar position which will be equal to normalized scrollrect position (0.1)
f) use that value to offset your localposition (something value*parallaxVector2), this should give you a nice cheap depth effect
Here's an example implementation
public class ScrolleRectDepthButton : MonoBehaviour
{
RectTransform content; // we'll grab it for size reference
RectTransform myRect;
public float parallaxAmount = 0.05f;
public Vector2 startPosition;
void Start()
{
myRect = GetComponent<RectTransform>();
startPosition = myRect.anchoredPosition;
ScrollRect scrollRect = GetComponentInParent<ScrollRect>();
content = scrollRect.content;
Scrollbar scrollbar = scrollRect.verticalScrollbar;
scrollbar.onValueChanged.AddListener(OnScrollbarMoved);
}
void OnScrollbarMoved(float f)
{
myRect.anchoredPosition = startPosition - (1 - f) * parallaxAmount * content.rect.height * Vector2.up;
}
}

Related

Unity - How to scroll a scrollbar for a ScrollRect smoothly?

I have a ScrollRect to which I add content to. When it reaches the point where the content is longer than the ScrollRect (ie when the ScrollBar's value changes from 0), I want the ScrollRect to scroll all the way down (I do this by tweening the ScrollBar's value until it reaches 0). However, my problem is that I can't figure out how to do this smoothly over time.
Here's my code snippet:
public void Update() {
if (scrollbar.size < 1 || scrollbar.value > 0) {
LeanTween.value(scrollbar.value, 0, duration).setOnUpdate((float val) => {
if (scrollbar.value == 0) {
LeanTween.cancel(this.gameObject);
} else {
scrollbar.value = val / scrollAdjustment;
}
});
}
}
I tried using "Time.deltaTime" and "Time.time" in place of duration and it did not seem to matter. Here's a gif of what happens:
(In this example, I used "duration" that had the value of 5 (the idea was to have the transition take 5 seconds) and "scrollAdjustment" was 50 but it did not seem to matter what I set either of these values to.
You can see it instantly snaps to the bottom. I'd like this to be a smooth transition. Any help is appreciated!
My settings:
Then here is me scrolling with my mouse wheel while the autoscroll feature is turned off (because I'm using Rewired, I am intercepting an input called "ZoomIn" and "ZoomOut" and add "0.01f * scrollSpeed" (where scrollSpeed is 15 in this case):
You shouldn't need to add any additional code to make the scroll bar function as the way you want it to. Try deactivating your script and mess with your scroll bar. Make sure you have your Number Of Steps On Your Scrollbar Component as 0 to make it smooth. If it's still not working, send some screenshots of your scroll gameobject to see if the rect is the problem or something else.

Unity, scalling the width of a dynamically created Gameobject in a a scroll view content box

I am trying to add 100 dynamically created buttons to a scroll view in Unity, but I have a problem letting the scroll view automatically adjust the width of the buttons to match the width of my screen.
When I tried to add the buttons manually it worked fine , but when I do this by code I get another results.
The code I am using :
public GameObject button;
public GameObject scrollviewcontents;
void Start()
{
for (int i =0; i<=100;i++) {
GameObject dbutton = Instantiate(button);
dbutton.name = i.ToString();
dbutton.transform.parent = scrollviewcontents.transform;
}
}
and The results I get :
Results
Results with comments
I just want the buttons to look like as they are added manually, any help ???
By default when instantiating an object the object keeps the same world space position, rotation and scale as before. try this instead:
dbutton.transform.SetParent(scrollviewcontents.transform, false);

Growing menu with scrollbar

I hate to ask such a generic question but I'm really stuck and super hoping someone can help me along the way. Here is the situation:
I'm making the GUI for a mobile app, portrait mode. I'm using canvas scalers to scale my canvasses with a reference width of 1080. This means I effectively don't know the height of my screen space.
What I want to create is a menu with a variable amount of items. The menu must be anchored to the bottom (with an offset margin) and grow upwards. So far I've been able to manage this using VerticalLayoutGroup and anchoring the rect transform to the bottom.
But my last requirement is that if the content would grow too big, a scrollbar would appear. The definition of the content being too big is: if it would extend the (unknown) screen height ( minus the offset margin of course). I hope the following image illustrates this much clearer:
I have a unity project here: https://ufile.io/v31br
Did you give a try to scrollView? here it is: https://unity3d.com/learn/tutorials/topics/user-interface-ui/scroll-view
You can use your vertical layout inside it and you will probably want to deactivate horizontal scroll and delete the horizontal slider.
Via script you can check its rectTransform height and compare it to your container's size, when reached maxHeight you can start managing your item's sizes
I assume you use the ScrollRect component as it is the right component to use in your case.
You can check the screen height with the Screen.height property.
Once you know the screen height you can compare it with your rect height and toggle the scrollbar with the ScrollRect.vertical property. You may have to change the ScrollRect.verticalScrollbarVisibility to permanent in order to make it work for you.
The answer Dave posted was close, but the problem is that the scrollview doesn't expand. I fixed it eventually by stretching the scrollview and resizing the parent manually as items are added. I set the anchors to the maximum size and adjust the sizeDelta.
public class MenuScript : MonoBehaviour
{
public int MenuItemCount;
public GameObject MenuItemPrefab;
public Transform MenuItemParent;
private RectTransform _rectTransform;
void Start()
{
_rectTransform = GetComponent<RectTransform>();
for (var i = 0; i <= MenuItemCount; i++)
{
GameObject instance = Instantiate(MenuItemPrefab, MenuItemParent, false);
instance.GetComponent<Text>().text = instance.name = "Item " + i;
float size = instance.transform.GetComponent<RectTransform>().sizeDelta.y;
TryExpandBy(size + 10);
}
}
private void TryExpandBy(float size)
{
var deltaY = _rectTransform.sizeDelta.y + size;
if (deltaY > 0) deltaY = 0;
_rectTransform.sizeDelta = new Vector2(_rectTransform.sizeDelta.x, deltaY);
}
}

move object and it's children out of camera in unity2d

I have made a gameobject together with some children gameobject to represent the information to show up when specific circumstances occurred.
I have already ajusted the position of the information gameobject(together with its' children) in the cameraarea. The thing is that I want to move the gameobject(together with its' children) out of the camera, maybe on top or maybe on left. Following is the scratch to demonstrate the position I want to put it:
So that I could move the information gameobject and its' children (Red box) with some movement effect when needed, I have no problem with moving it back but could find an elegant way to move it out of the camera when the game started.
Mostly because I don't know how to calculate the position out of the camera.
Maybe find the upper border of the camera and the size of the gameobject and its children?
I know I could do this by maybe add a marker gameobject to represent the downer border of the information gameobject, and move it until it's not visible, but is there a more elegant way?
Any ideas?
For this one, I would use the following trick: use any method (animation, coroutine, Update method...) to move your item out of screen the way you desire. Then you can use the OnBecameInvisible event which is called when the item does not need to be rendered on any camera anymore. The event will there be used to detect that the parent object moved out of screen, and that you want to stop the current movement. You then just need to define in this event that you want to stop the current moving behavior, and you will be done.
void OnBecameInvisible() {
// Stop moving coroutine, moving in Update or current animation.
}
There are probably more elegant ways of doing it as you said, but I think this method should be enough for what you want to achieve.
It took me time, but I found this way for you, attach this script to your gameObject:
public Renderer rend;
//drag the camera to the script in the inspector
public Camera camera1;
Vector3 bottomleft;
Vector3 topright;
void Start()
{
rend = GetComponent<Renderer>();
//the top-right point of the camera bounds
topright= camera1.ViewportToWorldPoint(new Vector3(0, 0, transform.position.z));
//the bottom-left point of the camera bounds
bottomleft = camera1.ViewportToWorldPoint(new Vector3(1, 1, transform.position.z));
StartCoroutine(MoveUp());
}
IEnumerator MoveUp()
{
//while the position and the height are lower that the Y of top right
while (transform.position.y + rend.bounds.size.y < topright.y)
{
//move the object to the new position (move it up)
transform.position = new Vector3(transform.position.x, transform.position.y + .01f, transform.position.z);
//and wait for 1/100 of a second
yield return new WaitForSecondsRealtime(.001f);
}
}
you can play with the WaitForSecondsRealtime value to change the velocity of moving.

Fake scrolling with JavaFX 8 ScrollPane

What I'm trying to do:
I'm trying to render a game board for a user using a canvas. The user
will be able to zoom.
Rendering the entire game board is impossible when the user is
zoomed in as the game board is very large. Instead I will render what
is onscreen every 1/30 sec.
I would like to create the illusion of the entire game board beings
inside a gui like the ScrollPane where the user can scroll with a
mouse.
In reality the ScrollPane will be linked to a single canvas exactly
the size of the viewport.
I'm not sure what the right way to go about this is. The scroll pane does not seem to have a property that allows you to pretend it has a large object in it. I could place a large canvas in the scroll pane but large canvases take up memory, as my crashes have suggested. Should I be using an AnchorPane or something? What's the proper way to do this?
It seems like putting an AnchorPane into the ScrollPane, setting that AnchorPane to the correct size (the size of the entire gameboard) works well to let the user scroll freely. From there all you have to do is put a canvas in the AnchorPane at the right place and keep moving it (and redrawing it) makes everything work out. To make it run smoothly I think you should render 100 to 500 pixels outside of the viewport of the ScrollPane. Here's some example code from my project:
public class GridViewPane {
/** ScrollPane that this grid exits in */
private ScrollPane gridScroll;
/** The anchor pane immediately inside of {#link #gridScroll}. The
* dimensions of this equals the dimensions of the {#link #can} if it was to
* render the entire grid at once */
private Pane gridView;
/** Exists in {#link #gridView} and is exactly the size of the viewport of
* {#link #gridScroll} */
private Canvas can;
/** A label the specifies what hex is currently moused-over */
private Label currentHexLabel;
public void update() {
// sets the canvas to the right size if needed
final Bounds viewportSize = gridScroll.getBoundsInLocal();
if (can == null || !can.getBoundsInLocal().equals(viewportSize)) {
can = new Canvas(viewportSize.getWidth(),
viewportSize.getHeight());
gc = can.getGraphicsContext2D();
}
// sets the anchorpane to the right size
final double[] dim = getPixleSizeOfGrid(w.columns(), w.rows(), r);
if (gridView == null) {
gridView = new AnchorPane();
gridScroll.setContent(gridView);
}
Bounds oldDim = gridView.getBoundsInLocal();
if (!(oldDim.getWidth() == dim[0]
&& oldDim.getHeight() == dim[1])) {
gridView.setPrefSize(dim[0], dim[1]);
}
// puts the canvas in the right position
if (!gridView.getChildren().contains(can))
gridView.getChildren().add(can);
double[] x = getXScreenRange();
double[] y = getYScreenRange();
can.relocate(x[0], y[0]);
// *********** Drawing Hexes ***********/
}
}