Skip to content

Commit 4dcf006

Browse files
committed
**New**:
- Added two new static event calls to UiService that are triggered when the app changes resolution and another trigger when changes screen orientation - The new *UiServiceMonoComponent* was added to the project for internal purposes, in order to support Unity's loop or generic *GameObjects* dependency code (e.g. the screen resolution trigger change) - Added new *AdjustScreenSizeFitter* to extend the ui behaviour of Unity's *ContentSizeFitter* in order to allow the *LayoutElement* to fit between the *LayoutElement.minSize* & *LayoutElement.flexibleSize*, values defined in the Unity's inspector **Changed**: - Renamed *UiPresenterData<T>* to *UiPresenter<T>* to make it less verbose
1 parent 6437be2 commit 4dcf006

File tree

8 files changed

+237
-9
lines changed

8 files changed

+237
-9
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this package will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
66

7+
## [0.11.0] - 2025-01-05
8+
9+
**New**:
10+
- Added two new static event calls to UiService that are triggered when the app changes resolution and another trigger when changes screen orientation
11+
- The new *UiServiceMonoComponent* was added to the project for internal purposes, in order to support Unity's loop or generic *GameObjects* dependency code (e.g. the screen resolution trigger change)
12+
- Added new *AdjustScreenSizeFitter* to extend the ui behaviour of Unity's *ContentSizeFitter* in order to allow the *LayoutElement* to fit between the *LayoutElement.minSize* & *LayoutElement.flexibleSize*, values defined in the Unity's inspector
13+
14+
**Changed**:
15+
- Renamed *UiPresenterData<T>* to *UiPresenter<T>* to make it less verbose
16+
717
## [0.10.0] - 2024-11-13
818

919
**New**:

Runtime/AdjustScreenSizeFitter.cs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
using System;
2+
using UnityEngine;
3+
using UnityEngine.EventSystems;
4+
using UnityEngine.UI;
5+
6+
namespace GameLovers.UiService
7+
{
8+
/// <summary>
9+
/// Resizes a RectTransform to fit the size of its content.
10+
/// </summary>
11+
/// <remarks>
12+
/// Similar to <see cref="ContentSizeFitter"/>, but rounds the size of its content between min and preferred sizes.
13+
/// Works better with explicit size anchors and not fitting size anchors
14+
/// </remarks>
15+
[AddComponentMenu("Layout/Adjust Size Fitter", 141)]
16+
[ExecuteAlways]
17+
[RequireComponent(typeof(RectTransform), typeof(LayoutElement))]
18+
public class AdjustScreenSizeFitter : UIBehaviour, ILayoutSelfController
19+
{
20+
[SerializeField] private RectOffset _padding = new RectOffset();
21+
[SerializeField] private RectTransform _canvasTransform;
22+
[SerializeField] private RectTransform _rectTransform;
23+
24+
private Vector2 _previousSize;
25+
26+
private RectTransform RectTransform
27+
{
28+
get
29+
{
30+
if (_rectTransform == null) _rectTransform = GetComponent<RectTransform>();
31+
return _rectTransform;
32+
}
33+
}
34+
35+
private RectTransform CanvasRectTransform
36+
{
37+
get
38+
{
39+
if (_canvasTransform == null) _canvasTransform = GetComponentInParent<Canvas>().GetComponent<RectTransform>();
40+
41+
_previousSize = _canvasTransform.sizeDelta;
42+
43+
return _canvasTransform;
44+
}
45+
}
46+
47+
protected override void OnEnable()
48+
{
49+
base.OnEnable();
50+
SetDirty();
51+
}
52+
53+
protected override void OnDisable()
54+
{
55+
LayoutRebuilder.MarkLayoutForRebuild(RectTransform);
56+
base.OnDisable();
57+
}
58+
59+
private void LateUpdate()
60+
{
61+
var previousSize = _previousSize;
62+
63+
if (previousSize == CanvasRectTransform.sizeDelta)
64+
{
65+
return;
66+
}
67+
68+
_previousSize = CanvasRectTransform.sizeDelta;
69+
SetDirty();
70+
}
71+
72+
/// <summary>
73+
/// Method called by the layout system. Has no effect
74+
/// </summary>
75+
public virtual void SetLayoutHorizontal() {}
76+
77+
/// <summary>
78+
/// Method called by the layout system. Has no effect
79+
/// </summary>
80+
public virtual void SetLayoutVertical() {}
81+
82+
protected override void OnTransformParentChanged()
83+
{
84+
base.OnTransformParentChanged();
85+
86+
SetDirty();
87+
}
88+
89+
private void SetDirty()
90+
{
91+
if (!IsActive())
92+
return;
93+
94+
var resolution = CanvasRectTransform.sizeDelta;
95+
var oldSize = RectTransform.sizeDelta;
96+
var newWidth = GetSize((int) RectTransform.Axis.Horizontal, resolution);
97+
var newHeight = GetSize((int) RectTransform.Axis.Vertical, resolution);
98+
99+
if (!Mathf.Approximately(newWidth, oldSize.x))
100+
{
101+
RectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newWidth);
102+
}
103+
104+
if (!Mathf.Approximately(newHeight, oldSize.y))
105+
{
106+
RectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, newHeight);
107+
}
108+
}
109+
110+
private float GetSize(int axis, Vector2 resolution)
111+
{
112+
var minSize = LayoutUtility.GetMinSize(RectTransform, axis);
113+
var maxSize = LayoutUtility.GetFlexibleSize(RectTransform, axis);
114+
var resolutionX = resolution.x - _padding.left - _padding.right;
115+
var resolutionY = resolution.y - _padding.top - _padding.bottom;
116+
117+
if (axis == 0)
118+
{
119+
if(resolutionX < minSize && minSize > 0) return minSize;
120+
if(resolutionX >= maxSize && maxSize > minSize && maxSize > 1) return maxSize;
121+
122+
return RectTransform.sizeDelta.x > resolutionX && resolutionX > 0 ? resolutionX : RectTransform.sizeDelta.x;
123+
}
124+
125+
if(resolutionY < minSize && minSize > 0) return minSize;
126+
if(resolutionY >= maxSize && maxSize > minSize && maxSize > 1) return maxSize;
127+
128+
return RectTransform.sizeDelta.y > resolutionY && resolutionY > 0 ? resolutionY : RectTransform.sizeDelta.y;
129+
}
130+
131+
#if UNITY_EDITOR
132+
protected override void OnValidate()
133+
{
134+
SetDirty();
135+
}
136+
#endif
137+
}
138+
}

Runtime/AdjustScreenSizeFitter.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/UiPresenter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ internal virtual void InternalClose(bool destroy)
8686
/// <remarks>
8787
/// Extends the <see cref="UiPresenter"/> behaviour to hold data of type <typeparamref name="T"/>
8888
/// </remarks>
89-
public abstract class UiPresenterData<T> : UiPresenter, IUiPresenterData where T : struct
89+
public abstract class UiPresenter<T> : UiPresenter, IUiPresenterData where T : struct
9090
{
9191
/// <summary>
9292
/// The Ui data defined when opened via the <see cref="UiService"/>

Runtime/UiService.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
using Cysharp.Threading.Tasks;
22
using System;
33
using System.Collections.Generic;
4-
using System.Linq;
5-
using System.Threading;
6-
using System.Threading.Tasks;
74
using UnityEngine;
5+
using UnityEngine.Events;
6+
using Object = UnityEngine.Object;
87

98
// ReSharper disable CheckNamespace
109

@@ -13,6 +12,9 @@ namespace GameLovers.UiService
1312
/// <inheritdoc />
1413
public class UiService : IUiServiceInit
1514
{
15+
public static readonly UnityEvent<DeviceOrientation, DeviceOrientation> OnOrientationChanged = new ();
16+
public static readonly UnityEvent<Vector2, Vector2> OnResolutionChanged = new ();
17+
1618
private readonly IUiAssetLoader _assetLoader;
1719
private readonly IDictionary<Type, UiConfig> _uiConfigs = new Dictionary<Type, UiConfig>();
1820
private readonly IList<Type> _visibleUiList = new List<Type>();
@@ -61,11 +63,12 @@ public void Init(UiConfigs configs)
6163
_uiParent = new GameObject("Ui").transform;
6264
_loadingSpinnerType = configs.LoadingSpinnerType;
6365

64-
GameObject.DontDestroyOnLoad(_uiParent.gameObject);
66+
_uiParent.gameObject.AddComponent<UiServiceMonoComponent>();
67+
Object.DontDestroyOnLoad(_uiParent.gameObject);
6568

6669
if (_loadingSpinnerType != null)
6770
{
68-
_ = LoadUiAsync(_loadingSpinnerType);
71+
LoadUiAsync(_loadingSpinnerType).Forget();
6972
}
7073
}
7174

@@ -249,9 +252,16 @@ public async UniTask<UiPresenter> OpenUiAsync(Type type)
249252
public async UniTask<UiPresenter> OpenUiAsync<TData>(Type type, TData initialData) where TData : struct
250253
{
251254
var ui = await GetOrLoadUiAsync(type);
252-
var uiPresenterData = ui as UiPresenterData<TData>;
255+
var uiPresenter = ui as UiPresenter<TData>;
256+
257+
if (uiPresenter == null)
258+
{
259+
Debug.LogError($"The UiPresenter {type} is not a UiPresenter<TData> type you. " +
260+
$"Implement it to allow it to open with initial defined data");
261+
return ui;
262+
}
253263

254-
uiPresenterData.InternalSetData(initialData);
264+
uiPresenter.InternalSetData(initialData);
255265
OpenUi(type);
256266

257267
return ui;

Runtime/UiServiceMonoComponent.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using UnityEngine;
2+
3+
namespace GameLovers.UiService
4+
{
5+
/// <summary>
6+
/// This class is responsible for updating the resolution and device orientation of the <see cref="UiService"/>
7+
/// </summary>
8+
public class UiServiceMonoComponent : MonoBehaviour
9+
{
10+
private Vector2 _resolution;
11+
private DeviceOrientation _orientation;
12+
13+
private void Awake()
14+
{
15+
_resolution = new Vector2(Screen.width, Screen.height);
16+
_orientation = Input.deviceOrientation;
17+
}
18+
19+
private void Update()
20+
{
21+
if (!Mathf.Approximately(_resolution.x, Screen.width) || !Mathf.Approximately(_resolution.y, Screen.height))
22+
{
23+
var previousResolution = _resolution;
24+
25+
_resolution = new Vector2(Screen.width, Screen.height);
26+
27+
UiService.OnResolutionChanged.Invoke(previousResolution, _resolution);
28+
}
29+
30+
switch (Input.deviceOrientation) {
31+
case DeviceOrientation.Unknown: // Ignore
32+
case DeviceOrientation.FaceUp: // Ignore
33+
case DeviceOrientation.FaceDown: // Ignore
34+
break;
35+
default:
36+
if (_orientation != Input.deviceOrientation)
37+
{
38+
var previousOrientation = _orientation;
39+
40+
_orientation = Input.deviceOrientation;
41+
42+
UiService.OnOrientationChanged.Invoke(previousOrientation, _orientation);
43+
}
44+
break;
45+
}
46+
}
47+
}
48+
}

Runtime/UiServiceMonoComponent.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "com.gamelovers.uiservice",
33
"displayName": "UiService",
44
"author": "Miguel Tomas",
5-
"version": "0.10.0",
5+
"version": "0.11.0",
66
"unity": "2022.3",
77
"license": "MIT",
88
"description": "This package provides a service to help manage an Unity's, game UI.\nIt allows to open, close, load, unload and request any Ui Configured in the game.\nThe package provides a Ui Set that allows to group a set of Ui Presenters to help load, open and close multiple Uis at the same time.\n\nTo help configure the game's UI you need to create a UiConfigs Scriptable object by:\n- Right Click on the Project View > Create > ScriptableObjects > Configs > UiConfigs",

0 commit comments

Comments
 (0)