using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using DG.Tweening; using UnityEngine.Events; [RequireComponent(typeof(EventTrigger))] public class ImageToggle : MonoBehaviour { public UnityEvent onToggle; [SerializeField] private bool m_isOn = false; public bool isOn{ get{ return m_isOn; } set{ Toggle(value); } } [SerializeField] private Image image; public Color onColor = Color.white; public Color offColor = Color.gray; [Header("Swap")] public Sprite onSprite; public Sprite offSprite; [Header("Tween Settings")] public float tweenDuration = 0.2f; public Ease tweenEase = Ease.OutQuad; public float enabledScale = 1f; public float disabledScale = 0.9f; public float hoverScale = 1.1f; private Tweener colorTween; private EventTrigger eventTrigger; void OnValidate(){ if(image == null){ image = GetComponent(); }else{ UpdateImageColor(); } } void Awake(){ // Ensure we have an image reference and set initial color instantly if(image == null){ image = GetComponent(); } UpdateImageColor(); } void Start() { eventTrigger = GetComponent(); EventTrigger.Entry entry = new EventTrigger.Entry(); entry.eventID = EventTriggerType.PointerDown; entry.callback.AddListener((data) => { Toggle(!m_isOn); }); eventTrigger.triggers.Add(entry); entry = new EventTrigger.Entry(); entry.eventID = EventTriggerType.PointerEnter; entry.callback.AddListener((data) => { float targetScale = (m_isOn ? enabledScale : disabledScale) * hoverScale; transform.DOScale(targetScale * hoverScale, tweenDuration).SetEase(tweenEase).SetUpdate(true); }); eventTrigger.triggers.Add(entry); entry = new EventTrigger.Entry(); entry.eventID = EventTriggerType.PointerExit; entry.callback.AddListener((data) => { float targetScale = m_isOn ? enabledScale : disabledScale; transform.DOScale(targetScale, tweenDuration).SetEase(tweenEase).SetUpdate(true); }); eventTrigger.triggers.Add(entry); } public void Toggle(bool value){ m_isOn = value; AnimateImageColor(); onToggle.Invoke(value); } void UpdateImageColor(){ image.color = m_isOn ? onColor : offColor; image.transform.localScale = Vector3.one * (m_isOn ? enabledScale : disabledScale); // Update sprite if sprites are assigned if(onSprite != null && offSprite != null){ image.sprite = m_isOn ? onSprite : offSprite; } } void AnimateImageColor(){ if(image == null) return; // Kill any existing tween on this image's color to avoid conflicts if(colorTween != null && colorTween.IsActive()){ colorTween.Kill(); } Color targetColor = m_isOn ? onColor : offColor; // Update sprite if sprites are assigned (sprite changes instantly, no animation) if(onSprite != null && offSprite != null){ image.sprite = m_isOn ? onSprite : offSprite; } // If duration is 0 or negative, just snap to the color if(tweenDuration <= 0f){ image.color = targetColor; return; } colorTween = image.DOColor(targetColor, tweenDuration) .SetEase(tweenEase).SetUpdate(true); AnimateImageScale(); } void AnimateImageScale(){ if(image == null) return; float targetScale = m_isOn ? enabledScale : disabledScale; image.transform.DOScale(targetScale, tweenDuration).SetEase(tweenEase).SetUpdate(true); } }