A common procedure in a game is to standardize the behavior of buttons when pressed/hovered/disabled, etc. In Unity’s uGUI we can create a generic animator for every button in the game, setting the Button’s transition to “Animation”. This animator can slightly scale the button on hover, reduce and darken it on press, apply alpha on disable, etc.
It is also very common for buttons to have different sprites when pressed, hovered, etc. To this end, we can use the “Sprite Swap” transition. However, we cannot use both Sprite Swap and Animation! This makes it impossible to keep a generic behavior with personalized sprites.
I believe this is a common enough need that it should be implemented natively. I posted a question here and the best option yet was to create a new button script (inheriting from Button) and overriding/recreating DoStateTransition or whichever method is best suited for this.
Is there a “best” way to do this? Is it a planned feature?
if its set up as a animation you can change the sprite via the animation window as well. Just add the image .sprite to the animations and it will switch between them. |
If the state animations contain sprite changes they will stop being generic right then. That would require an animator and set of animations for each different button (because each button has different sprites). The scalings/tints/etc must be the same for every button (a single Animator), but each button has its own set of sprites.
The best I created is the following script. It only mixes Animation and SpriteSwap, and requires that you set the sprites in the SpriteSwap transition of the button (in the inspector) and then change it to the Animation transition when finished. This is because I haven’t found a way to execute the transition Animations correctly from code, so I rely on the internal implementation of DoStateTransition() to do that. On the other hand, sprite swapping is easy enough to do.
using UnityEngine;
using UnityEngine.UI;
public class SpriteSwapperButton : Button
{
private Sprite normalSprite;
protected override void Awake()
{
base.Awake();
normalSprite = image.sprite;
}
protected override void DoStateTransition (Selectable.SelectionState state, bool instant)
{
base.DoStateTransition(state, instant);
Sprite newSprite = null;
switch (state)
{
case Selectable.SelectionState.Normal:
newSprite = normalSprite;
break;
case Selectable.SelectionState.Highlighted:
newSprite = this.spriteState.highlightedSprite;
break;
case Selectable.SelectionState.Pressed:
newSprite = this.spriteState.pressedSprite;
break;
case Selectable.SelectionState.Disabled:
newSprite = this.spriteState.disabledSprite;
break;
}
if (newSprite != null) {
image.sprite = newSprite;
}
}
}
Warning: This is far from perfect, and might create some problem I’m not aware of.
If you want to use this script but don’t want to remove your existing Button components first, set the inspector in Debug mode (beside the lock symbol in the top right corner, press and select “Debug” instead of “Normal”) and then exchange the Button script for the SpriteSwapperButton. If done correctly, this will retain all values from your Button.
Looking forward to other/better approaches to this!
I’ve got the same problem, but I want to use animations and Tint color at the same time. My solution is, to do the animation handling via a script. It is pretty simple, but maybe it helps somebody as a starting point:
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
public class ButtonAnimator : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler {
private Animator buttonAnimator;
// Use this for initialization
void Start () {
buttonAnimator = GetComponent<Animator>();
}
public void OnPointerEnter (PointerEventData eventData) {
buttonAnimator.SetTrigger("Highlighted");
}
public void OnPointerExit (PointerEventData eventData) {
buttonAnimator.SetTrigger("Normal");
}
public void OnPointerDown (PointerEventData eventData) {
buttonAnimator.SetTrigger("Pressed");
}
}
Not complete, because I will use other states, but I guess an easy way to do it