Edited at

iPhoneX対応:UnityでNGUIのAnchorをセーフエリア分ずらす

More than 1 year has passed since last update.


環境

Unity 4.7.2f1

NGUI 3.7.8


はじめに

今月からiPhoneX対応始めました。(残り1月無いよ...)

▽Qiita - iPhone Xのセーフエリアやマージン幅について

https://qiita.com/usagimaru/items/761e9a5f3d78b1939df8

セーフエリアの対応にてNGUIのAnchorをずらす作業を行ったのでまとめておきます。

セーフエリアの取得方法はここでは触れません。


先にまとめ

        // Topのセーフエリア対応を無視するか

[SerializeField] bool m_IsIgnoreTop;

// Bottomのセーフエリア対応を無視するか
[SerializeField] bool m_IsIgnoreBottom;

void Awake()
{
// UIAnchorを使っている場合(relative offset考慮してない)
UIAnchor anchor = gameObject.GetComponent<UIAnchor>();
if(anchor != null){
SetAnchorOffset (anchor);
return;
}

// UIRectを使っている場合
UIRect rect = gameObject.GetComponent<UIRect>();
if (rect != null) {
SetAnchorAbsolute (rect);
return;
}
}

/// <summary>
/// anchorのoffsetを設定する
/// (UIAnchorは非推奨(
/// </summary>
void SetAnchorOffset(UIAnchor anchor){
ScreenUtility.EdgeInsets edge = ScreenUtility.GetSafeAreaUI();

UIAnchor.Side side = anchor.side;
Vector2 offset = anchor.pixelOffset;

switch (side) {
case UIAnchor.Side.Bottom:
case UIAnchor.Side.BottomLeft:
case UIAnchor.Side.BottomRight:
if (!m_IsIgnoreBottom) {
anchor.pixelOffset.Set(offset.x, offset.y + edge.bottom);
}
break;
case UIAnchor.Side.Top:
case UIAnchor.Side.TopLeft:
case UIAnchor.Side.TopRight:
if (!m_IsIgnoreTop) {
anchor.pixelOffset.Set(offset.x, offset.y - edge.top);
}
break;
}
}

/// <summary>
/// anchorのabsoluteを設定する
/// </summary>
/// <param name="rect">Rect.</param>
void SetAnchorAbsolute(UIRect rect){
ScreenUtility.EdgeInsets edge = ScreenUtility.GetSafeAreaUI();

// top基準:1 center基準:0.5 bottom基準:0
float topRelative = rect.topAnchor.relative;
float bottomRelative = rect.bottomAnchor.relative;

float topMovingValue = 0f;
float bottomMovingValue = 0f;

if (topRelative == 1f && bottomRelative == 1f) {
topMovingValue -= edge.top;
bottomMovingValue -= edge.top;
} else if (topRelative == 0f && bottomRelative == 0f){
topMovingValue += edge.bottom;
bottomMovingValue += edge.bottom;
}else if(topRelative == 1f && bottomRelative == 0f){
topMovingValue -= edge.top;
bottomMovingValue += edge.bottom;
}

if (!m_IsIgnoreTop) {
rect.topAnchor.absolute += (int)topMovingValue;
}
if (!m_IsIgnoreBottom) {
rect.bottomAnchor.absolute += (int)bottomMovingValue;
}
}

これをセーフエリア対応したいAnchorがattachされているGameObjectにattachします。


解説


legacyの「UIAnchor」の対応

▽NGUIリファレンス - UIAnchor

http://tasharen.com/ngui/docs/class_u_i_anchor.html



legacyなのでこれ以上使わないようにと警告が表示されます。

置き換えたいところですが工数がエライことになるのでこれはそっとしておく...。

このクラスはenum SideでAnchorをつける位置を指定します。

SideがBottom系であればセーフエリアのBottom分底上げし、SideがTop系であればセーフエリアのTop分を下にずらす処理を入れることで対応しました。


「UIRect」の対応

▽NGUIリファレンス - UIRect

http://tasharen.com/ngui/docs/class_u_i_rect.html



UIWidgetだけではなく、UIRectから派生しているクラスであれば基底であるUIRectをGetComponentすることができます。

    // UIRectを使っている場合

UIRect rect = gameObject.GetComponent<UIRect>();
if (rect != null) {
SetAnchorAbsolute (rect);
return;
}

UIRectには「topAnchor」「bottomAnchor」「leftAnchor」「rightAnchor」の4つのAnchorPointがあります。

今回は「topAnchor」「bottomAnchor」を使います。

UIRect の Anchor は relative の値によってAnchorの位置を指定します。

指定したアンカーの位置とrelativeの関係性は以下の通りでした。

・Target's Top を設定していれば relative の値は 1f

・Target's Center を設定していれば relative の値は 0.5f

・Target's Bottom を設定していれば relative の値は 0f

それぞれのAnchorPointにTarget's Bottomを指定していればセーフエリアのBottom分底上げし、Target's Topを指定していればセーフエリアのTop分を下にずらす処理を入れることで対応しました。

また、TopのAnchorPointにTarget's Topしている、かつBottomのAnchorPointにTarget's Bottomを設定していれば領域が狭まるように対応を入れました。


さいごに

あとはこれをattachしていくだけ...と思いきや、

・コードで位置ずらしている

・legacyとそうでないAnchorが混在している

・親オブジェクトAnchorと子オブジェクトのAnchorが別のTarget見ている

などなど、一筋縄ではいかないもので...