Carousel Slider in Unity 3D
Table of Contents
Hi, this is my second post, and I hope it could be useful to you. Using this component is really easy, and I’ll show you how to do it step by step. First, I’m going to give you the C# code and then I will explain how it works.
##
Carousel.cs
using UnityEngine;
using System.Collections;
public class Carousel : MonoBehaviour
{
private static int _nearestIndex = 0;
private static float _minMoveTreshold = 20f;
private static float _newScroll = 0;
private static AnimationCurve _miniTransitionCurve;
public static bool Draw(Rect rect, ref float scroll, out int selectedIndex, float growMultiplyer, float slidesDistance, Texture2D[] slides, float size, float transitionTime, bool startTransition)
{
CheckMoves();
selectedIndex = _nearestIndex;
if (_miniTransitionCurve != null && _miniTransitionCurve.Evaluate(Time.time) < 0.90f)
{
if (Input.touchCount < 1)
{
scroll = Mathf.Lerp(scroll, _newScroll, _miniTransitionCurve.Evaluate(Time.time));
}
}
if (startTransition)
{
_miniTransitionCurve = AnimationCurve.Linear(Time.time, 0, Time.time + transitionTime, 1);
_miniTransitionCurve.preWrapMode = WrapMode.Clamp;
_miniTransitionCurve.postWrapMode = WrapMode.Clamp;
}
GUI.BeginGroup(rect);
{
GUI.BeginGroup(new Rect(-scroll, rect.height / 2 - size * growMultiplyer, int.MaxValue, size * growMultiplyer * 2));
{
float minDistance = float.MaxValue;
for (int i = 0; i < slides.Length; i++)
{
float relativePosition = rect.width / 2 - size / 2 + i * (size + slidesDistance) + size / 2 - scroll;
float grow = 1 + Ratio(relativePosition, rect.width) * (growMultiplyer - 1);
GUI.DrawTexture(new Rect(rect.width / 2 - size * grow / 2 + i * (size + slidesDistance), size * growMultiplyer - size * grow / 2, size * grow, size * grow), slides[i]);
if (GUI.Button(new Rect(rect.width / 2 - size * grow / 2 + i * (size + slidesDistance), size * growMultiplyer - size * grow / 2, size * grow, size * grow), "", GUIStyle.none))
{
if (!_moved)
{
selectedIndex = i;
return true;
}
}
float distance = Mathf.Abs(relativePosition - rect.width / 2);
if (distance < minDistance)
{
minDistance = distance;
_nearestIndex = i;
_newScroll = scroll + (relativePosition - rect.width / 2);
}
}
}
GUI.EndGroup();
}
GUI.EndGroup();
return false;
}
private static Vector2 _startPosition;
private static bool _moved = false;
private static void CheckMoves()
{
if (Input.touchCount > 0)
{
if (Input.touches[0].phase == TouchPhase.Began)
{
_moved = false;
_startPosition = Input.touches[0].position;
}
if (Input.touches[0].phase == TouchPhase.Moved || Input.touches[0].phase == TouchPhase.Ended || Input.touches[0].phase == TouchPhase.Canceled)
{
if (Vector2.Distance(Input.touches[0].position, _startPosition) > _minMoveTreshold)
{
_moved = true;
}
}
}
}
private static float Ratio(float pos, float length)
{
if (pos <= length / 2)
return pos / (length / 2);
else
return (length - pos) / (length / 2);
}
}
The CheckMoves function checks if we are scrolling or selecting a slide. If we move our hand and our touch movement was bigger than the threshold, we are scrolling. As you can see, the Draw function is static, so you don’t need to attach this component to an existing game object. This function does all the work for you, and all you have to do is place it in an OnGUI() method where you want to draw a carousel. If you didn’t catch what I just said, here is the code:
Carousel.Draw(rect, ref scroll, out selectedIndex, growMultiplyer, slidesDistance, slides, size, transitionTime, startTransition);
If you don’t place it in the OnGUI function, it will cause errors. You should also implement a function to handle the input in your own script and then pass the scroll value to the draw function.
##
My Method
I used basic math to do it. Many may think this is a bad idea, but it’s awesome 😎. My idea was something like this:
I implemented two functions, Ratio
and AngleRadian
, to handle the scroll and resizes in both linear and curved styles. But that’s not the end of it. For scrolling the carousel, you should implement your own input handling function. For those who need help with this part, here is an example:
// Carousel Scroll
private float _scroll;
private float _startPosition;
private float _startScroll;
private void HandleInput(int min, int max)
{
// Touch Input
if (Input.touchCount > 0)
{
Touch touch = Input.touches[0];
if (touch.phase == TouchPhase.Began)
{
_startPosition = touch.position.x;
_startScroll = _scroll;
}
if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
{
_scroll = _startScroll - (touch.position.x - _startPosition) * 2;
}
}
// Keyboard Input
if (Input.GetKey(KeyCode.LeftArrow))
_scroll -= 20;
if (Input.GetKey(KeyCode.RightArrow))
_scroll += 20;
_scroll = Mathf.Clamp(_scroll, min, max);
}
Just put this in the Update function. There you go! If you have any problems or questions, just comment in the form below. Good luck!