Help us understand the problem. What is going on with this article?

[Unity] uGUIのボタン押し下げ時にオーバーレイのテキストも一緒に下げる

More than 3 years have passed since last update.

内容

押し下げ時にボタンの画像を変えるような仕様で
さらにボタン上にダイナミックフォントでテキストを描画しているとする。
例えば以下のようなボタン。

image

左が通常の状態でボタンを押すと、押し下げを表現してボタンの高さが変わる。
このときボタン上のテキストも追従して移動してほしい。

ButtonのTransitionをAnimationにして、ボタンと同じレイヤにImageを置き、
そのImageを表示/非表示する方法も考えられるが、なんだか面倒。

プログラマ視点で簡単な実装を探る。

実装内容

uGUIはオープンソースなので実装内容を確認することができる。
https://bitbucket.org/Unity-Technologies/ui

Buttonの実装でオーバライドできるような処理で使えるものはないか調査しました。
実装としては以下のようになりました。

MyButton.cs
using UnityEngine;
using UnityEngine.UI;

public class MyButton : Button
{
    const float POSITION_Y_DISABLE = -6.7f;

    [SerializeField]
    RectTransform _rectTransformTextRoot;

    Vector2 _positionDisable = new Vector2(0f, POSITION_Y_DISABLE);

    protected override void DoStateTransition(SelectionState state, bool instant)
    {
        base.DoStateTransition(state, instant);

        switch(state)
        {
            case SelectionState.Highlighted:
            case SelectionState.Normal:
                _rectTransformTextRoot.anchoredPosition = Vector2.zero;
                break;
            case SelectionState.Pressed:
                _rectTransformTextRoot.anchoredPosition = _positionDisable;
                break;
            case SelectionState.Disabled:
                _rectTransformTextRoot.anchoredPosition = _positionDisable;
                break;
        }
    }
}

ButtonのTransitionをSpriteSwapにして、通常のように各状態にSpriteを設定する。
DoStateTransition()は状態変更時にコールされるので、この関数をオーバライドしてハンドリングする。

ButtonをカスタマイズするとSerializeFieldが表示されないので
エディタ拡張してインスペクターの表示を変更する。
ここは手抜きでベースのものを利用して、追加分だけを定義する。

MyButtonEditor.cs
using UnityEditor;
using UnityEditor.UI;

[CustomEditor(typeof(MyButton))]
public class MyButtonEditor : ButtonEditor
{
    MyButton _target;
    SerializedProperty _propertyRectTransformTextRoot;

    protected override void OnEnable()
    {
        base.OnEnable();

        _target = target as MyButton;
        _propertyRectTransformTextRoot = serializedObject.FindProperty("_rectTransformTextRoot");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        EditorGUILayout.Space();

        serializedObject.Update();
        EditorGUILayout.PropertyField(_propertyRectTransformTextRoot);
        serializedObject.ApplyModifiedProperties();
    }
}

Buttonの代わりにカスタマイズしたButtonをアタッチする。

以下のようにボタンの押し下げと連動してテキストも移動する。

Screencast-2016-11-02a3.gif

注意

uGUIのテキストのアンカーなどの設定によっては実装が異なることもあります。
適時、実装を変えてください。

あとがき

IPointerClickHandlerなどのインタフェースを実装して
押し下げのイベントをハンドリングすることはできる。

しかし、イベントインタフェースを調べてみても無効の状態へ遷移したことをハンドリングするものがない。
今回のボタンでは無効のときも押し下げにして押せないことを表現したかったので
このような実装になりました。

もし押し下げ、押し上げ、ハイライト、ノーマルの状態のみであれば
IPointerClickHandler系のインタフェースを実装することで対応することは可能です。

また今回のような手抜きではなく、Transitionするときにアニメーションしたり等
もっと仕様を盛り込みたいときは一からボタンクラスを作ることも可能です。

akerusoft
会社に所属していないので業務内で許される時間内で書いた備忘録のようなものが多数です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away