触ると表示され放置すると消えるスクロールバー
概要
アプリによくあるような、普段は見えないが、スクロール領域を動かしたらフェードインで表示され、スクロールが終わるとフェードアウトで消えていくようなスクロールバーを作った。
ステートパターンで非表示/フェードイン/表示/フェードアウトを切り替えている。
ステートが変わるたびにオブジェクトが生成されるのを避けるため、各ステートは初回で生成してしまっている。
フェード処理、遅延処理にはDoTweenを使用している。
パラメータ
- AutoFadeScrollbar.handle:表示・非表示となる操作用ハンドル画像。Sliding Areaは最初から非表示にしておく
- FadeInState.fadeDuration:フェードインにかかる時間
- ShowState.showDuration:表示し続ける時間
- FadeOutState.fadeDuration:フェードアウトにかかる時間
コード
以下を作成しScrollbarコンポーネントとともにアタッチする。
#region以下はステートの実装部。
using DG.Tweening; using UnityEngine; using UnityEngine.UI; /// <summary> /// 動かしたときに表示され、自動で消えるスクロールバー /// </summary> [RequireComponent(typeof(Scrollbar))] public class AutoFadeScrollbar : MonoBehaviour { [SerializeField] private Scrollbar scrollbar; [SerializeField] private Image handle; /// <summary> /// 初期処理 /// </summary> private void Awake() { var context = new Context(handle); scrollbar.onValueChanged.AddListener(_ => context.OnScroll()); } #region ハンドルコンテキストとステートのクラス定義 private enum HandleState { Hide, FadeIn, Show, FadeOut } /// <summary> /// コンテキストクラス /// </summary> private class Context { /// <summary> /// ハンドル画像 /// </summary> public readonly Image Image; private IHandleState currentState; /// <summary> /// ステートリスト /// 毎回newしたくないので状態は保持しておく /// </summary> private readonly IHandleState[] stateList = { new HideState(), new FadeInState(), new ShowState(), new FadeOutState() }; /// <summary> /// コンストラクタ /// ハンドル画像の取得と初期Stateのセット /// </summary> /// <param name="image"></param> public Context(Image image) { Image = image; ChangeState(HandleState.Hide); } /// <summary> /// ハンドル状態の更新 /// </summary> /// <param name="newState"></param> public void ChangeState(HandleState newState) { currentState = stateList[(int)newState]; currentState.Initialize(this); } /// <summary> /// 動かしたとき各ステートの実行 /// </summary> public void OnScroll() { currentState.OnScroll(this); } } /// <summary> /// ハンドルの状態を表すインターフェース /// </summary> private interface IHandleState { /// <summary> /// ステート遷移時の初期化 /// </summary> /// <param name="context"></param> void Initialize(Context context); /// <summary> /// 動かしたとき /// </summary> /// <param name="context"></param> void OnScroll(Context context); } /// <summary> /// 非表示状態 /// </summary> private class HideState : IHandleState { private readonly Color clearColor; /// <summary> /// コンストラクタ /// 透明色のキャッシュ /// </summary> public HideState() { clearColor = Color.white; clearColor.a = 0; } /// <summary> /// 完全に非表示化 /// </summary> /// <param name="context"></param> public void Initialize(Context context) { context.Image.color = clearColor; } /// <summary> /// 表示中に切り替え /// </summary> /// <param name="context"></param> public void OnScroll(Context context) { context.ChangeState(HandleState.FadeIn); } } /// <summary> /// フェード表示中 /// </summary> private class FadeInState : IHandleState { // フェード時間 private float fadeDuration = 0.2f; /// <summary> /// フェード表示の実行 /// </summary> /// <param name="context"></param> public void Initialize(Context context) { DOTween.ToAlpha(() => context.Image.color, color => context.Image.color = color, 1, fadeDuration) .OnComplete(() => context.ChangeState(HandleState.Show)); } public void OnScroll(Context context) { } } /// <summary> /// 表示中 /// </summary> private class ShowState : IHandleState { // 表示し続ける時間 private float showDuration = 3f; private Tween _tween; private readonly Color clearColor; /// <summary> /// コンストラクタ /// 表示色のキャッシュ /// </summary> public ShowState() { clearColor = Color.white; } /// <summary> /// 表示後、徐々にフェードアウトさせる /// </summary> /// <param name="context"></param> public void Initialize(Context context) { context.Image.color = clearColor; _tween = DOVirtual.DelayedCall(showDuration, () => context.ChangeState(HandleState.FadeOut)); } /// <summary> /// スクロールされると表示時間をリセット /// </summary> /// <param name="context"></param> public void OnScroll(Context context) { _tween.Restart(); } } /// <summary> /// フェードアウト中 /// </summary> private class FadeOutState : IHandleState { private float fadeDuration = 0.4f; /// <summary> /// フェードアウトの実行 /// </summary> /// <param name="context"></param> public void Initialize(Context context) { DOTween.ToAlpha(() => context.Image.color, color => context.Image.color = color, 0, fadeDuration) .OnComplete(() => context.ChangeState(HandleState.Hide)); } /// <summary> /// スクロールすると再表示 /// </summary> /// <param name="context"></param> public void OnScroll(Context context) { context.ChangeState(HandleState.FadeIn); } } #endregion }