透明小地图&列表点击切换&海拔图头像位移
This commit is contained in:
1 parent
bf48989a9c
commit
6ec4c0101b
114 files changed
+12787
-6517
No files matched your search
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fab03186a79d74df99ffa7147294ea61
|
||||
folderAsset: yes
|
||||
timeCreated: 1579763866
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,129 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
using UnityEngine.UI;
|
||||
using UnityEditor.AnimatedValues;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
[CustomEditor(typeof(RecyclableScrollRect), true)]
|
||||
[CanEditMultipleObjects]
|
||||
/// <summary>
|
||||
/// Custom Editor for the Recyclable Scroll Rect Component which is derived from Scroll Rect.
|
||||
/// </summary>
|
||||
|
||||
public class RecyclableScrollRectEditor : Editor
|
||||
{
|
||||
SerializedProperty m_Content;
|
||||
SerializedProperty m_MovementType;
|
||||
SerializedProperty m_Elasticity;
|
||||
SerializedProperty m_Inertia;
|
||||
SerializedProperty m_DecelerationRate;
|
||||
SerializedProperty m_ScrollSensitivity;
|
||||
SerializedProperty m_Viewport;
|
||||
SerializedProperty m_OnValueChanged;
|
||||
|
||||
//inherited
|
||||
SerializedProperty _protoTypeCell;
|
||||
SerializedProperty _selfInitialize;
|
||||
SerializedProperty _direction;
|
||||
SerializedProperty _type;
|
||||
|
||||
AnimBool m_ShowElasticity;
|
||||
AnimBool m_ShowDecelerationRate;
|
||||
|
||||
RecyclableScrollRect _script;
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_script = (RecyclableScrollRect)target;
|
||||
|
||||
m_Content = serializedObject.FindProperty("m_Content");
|
||||
m_MovementType = serializedObject.FindProperty("m_MovementType");
|
||||
m_Elasticity = serializedObject.FindProperty("m_Elasticity");
|
||||
m_Inertia = serializedObject.FindProperty("m_Inertia");
|
||||
m_DecelerationRate = serializedObject.FindProperty("m_DecelerationRate");
|
||||
m_ScrollSensitivity = serializedObject.FindProperty("m_ScrollSensitivity");
|
||||
m_Viewport = serializedObject.FindProperty("m_Viewport");
|
||||
m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
|
||||
|
||||
//Inherited
|
||||
_protoTypeCell = serializedObject.FindProperty("PrototypeCell");
|
||||
_selfInitialize = serializedObject.FindProperty("SelfInitialize");
|
||||
_direction = serializedObject.FindProperty("Direction");
|
||||
_type = serializedObject.FindProperty("IsGrid");
|
||||
|
||||
m_ShowElasticity = new AnimBool(Repaint);
|
||||
m_ShowDecelerationRate = new AnimBool(Repaint);
|
||||
SetAnimBools(true);
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
m_ShowElasticity.valueChanged.RemoveListener(Repaint);
|
||||
m_ShowDecelerationRate.valueChanged.RemoveListener(Repaint);
|
||||
}
|
||||
|
||||
void SetAnimBools(bool instant)
|
||||
{
|
||||
SetAnimBool(m_ShowElasticity, !m_MovementType.hasMultipleDifferentValues && m_MovementType.enumValueIndex == (int)ScrollRect.MovementType.Elastic, instant);
|
||||
SetAnimBool(m_ShowDecelerationRate, !m_Inertia.hasMultipleDifferentValues && m_Inertia.boolValue, instant);
|
||||
}
|
||||
|
||||
void SetAnimBool(AnimBool a, bool value, bool instant)
|
||||
{
|
||||
if (instant)
|
||||
a.value = value;
|
||||
else
|
||||
a.target = value;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
SetAnimBools(false);
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_direction);
|
||||
EditorGUILayout.PropertyField(_type, new GUIContent("Grid"));
|
||||
if (_type.boolValue)
|
||||
{
|
||||
string title = _direction.enumValueIndex == (int)RecyclableScrollRect.DirectionType.Vertical ? "Coloumns" : "Rows";
|
||||
_script.Segments = EditorGUILayout.IntField(title, _script.Segments);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_selfInitialize);
|
||||
EditorGUILayout.PropertyField(m_Viewport);
|
||||
EditorGUILayout.PropertyField(m_Content);
|
||||
EditorGUILayout.PropertyField(_protoTypeCell);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_MovementType);
|
||||
if (EditorGUILayout.BeginFadeGroup(m_ShowElasticity.faded))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Elasticity);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFadeGroup();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Inertia);
|
||||
if (EditorGUILayout.BeginFadeGroup(m_ShowDecelerationRate.faded))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_DecelerationRate);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFadeGroup();
|
||||
|
||||
EditorGUILayout.PropertyField(m_ScrollSensitivity);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_OnValueChanged);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74168ba3b38714896bfecd0206751ad1
|
||||
timeCreated: 1579677840
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public static class RecyclableScrollViewEditorTool
|
||||
{
|
||||
const string PrefabPath = "Assets/Recyclable Scroll Rect/Main/Prefab/Recyclable Scroll View.prefab";
|
||||
|
||||
[MenuItem("GameObject/UI/Recyclable Scroll View")]
|
||||
private static void CreateRecyclableScrollView()
|
||||
{
|
||||
GameObject selected = Selection.activeGameObject;
|
||||
|
||||
//If selected isn't a UI gameobject then find a Canvas
|
||||
if (!selected || !(selected.transform is RectTransform))
|
||||
{
|
||||
selected = GameObject.FindObjectOfType<Canvas>().gameObject;
|
||||
}
|
||||
|
||||
if (!selected) return;
|
||||
|
||||
GameObject asset = AssetDatabase.LoadAssetAtPath(PrefabPath, typeof(GameObject)) as GameObject;
|
||||
|
||||
GameObject item = Object.Instantiate(asset);
|
||||
item.name = "Recyclable Scroll View";
|
||||
|
||||
item.transform.SetParent(selected.transform);
|
||||
item.transform.localPosition = Vector3.zero;
|
||||
Selection.activeGameObject = item;
|
||||
Undo.RegisterCreatedObjectUndo(item, "Create Recycalable Scroll view");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf7388e878b9648048580d3339aa57e6
|
||||
timeCreated: 1580287998
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c857a3657dfd4bcb98387044af3ae7d
|
||||
folderAsset: yes
|
||||
timeCreated: 1580416784
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 907 B |
@@ -0,0 +1,107 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b7325ceb7a524d43bf38b93ad0c7118
|
||||
timeCreated: 1580416733
|
||||
licenseType: Store
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapU: -1
|
||||
wrapV: -1
|
||||
wrapW: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: iPhone
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Android
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfa1633e450e04d51b559a09b45e4efd
|
||||
folderAsset: yes
|
||||
timeCreated: 1580414924
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,234 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1527163063724600}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1253332298834758
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 224953711503076072}
|
||||
m_Layer: 5
|
||||
m_Name: Content
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!1 &1527163063724600
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 224141822819573504}
|
||||
- component: {fileID: 222122610330645636}
|
||||
- component: {fileID: 114310977074674660}
|
||||
- component: {fileID: 114035338358051486}
|
||||
m_Layer: 5
|
||||
m_Name: Recyclable Scroll View
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!1 &1740122973338780
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 224516841076241162}
|
||||
- component: {fileID: 114664610104649842}
|
||||
- component: {fileID: 222300018684681582}
|
||||
- component: {fileID: 114086589109956998}
|
||||
m_Layer: 5
|
||||
m_Name: Viewport
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &114035338358051486
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1527163063724600}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 0.392}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
--- !u!114 &114086589109956998
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1740122973338780}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
--- !u!114 &114310977074674660
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1527163063724600}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 248d9fa993d3e44daa165a75b0063088, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Content: {fileID: 224953711503076072}
|
||||
m_Horizontal: 0
|
||||
m_Vertical: 1
|
||||
m_MovementType: 1
|
||||
m_Elasticity: 0.1
|
||||
m_Inertia: 1
|
||||
m_DecelerationRate: 0.135
|
||||
m_ScrollSensitivity: 1
|
||||
m_Viewport: {fileID: 224516841076241162}
|
||||
m_HorizontalScrollbar: {fileID: 0}
|
||||
m_VerticalScrollbar: {fileID: 0}
|
||||
m_HorizontalScrollbarVisibility: 0
|
||||
m_VerticalScrollbarVisibility: 0
|
||||
m_HorizontalScrollbarSpacing: 0
|
||||
m_VerticalScrollbarSpacing: 0
|
||||
m_OnValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.ScrollRect+ScrollRectEvent, UnityEngine.UI, Version=1.0.0.0,
|
||||
Culture=neutral, PublicKeyToken=null
|
||||
IsGrid: 0
|
||||
PrototypeCell: {fileID: 0}
|
||||
SelfInitialize: 1
|
||||
Direction: 0
|
||||
_segments: 0
|
||||
--- !u!114 &114664610104649842
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1740122973338780}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -1200242548, guid: f70555f144d8491a825f0804e09c671c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_ShowMaskGraphic: 0
|
||||
--- !u!222 &222122610330645636
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1527163063724600}
|
||||
--- !u!222 &222300018684681582
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1740122973338780}
|
||||
--- !u!224 &224141822819573504
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1527163063724600}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 224516841076241162}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -122.19763, y: -9.611036}
|
||||
m_SizeDelta: {x: 200, y: 200}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!224 &224516841076241162
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1740122973338780}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 224953711503076072}
|
||||
m_Father: {fileID: 224141822819573504}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!224 &224953711503076072
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1253332298834758}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 224516841076241162}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0.000021875792}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c01abf790e1a42ca8d10525f571cab5
|
||||
timeCreated: 1580414917
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ede93dd89924c46df91d86c4d59f5e62
|
||||
folderAsset: yes
|
||||
timeCreated: 1580017437
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 954ddfcde675c304baf014480514e599
|
||||
folderAsset: yes
|
||||
timeCreated: 1598985910
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
/// <summary>
|
||||
/// Interface for creating a Cell.
|
||||
/// Prototype Cell must have a monobeviour inheriting from ICell
|
||||
/// </summary>
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
public interface ICell
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4ad8716ee240469ca93bc22214fddfe
|
||||
timeCreated: 1577787384
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
/// <summary>
|
||||
/// Interface for creating DataSource
|
||||
/// Recyclable Scroll Rect must be provided a Data source which must inherit from this.
|
||||
/// </summary>
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
public interface IRecyclableScrollRectDataSource
|
||||
{
|
||||
int GetItemCount();
|
||||
void SetCell(ICell cell, int index);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ef29d4c7afcd43079f3cfc4d4e1ecbf
|
||||
timeCreated: 1580410346
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,154 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry for the recycling system. Extends Unity's inbuilt ScrollRect.
|
||||
/// </summary>
|
||||
public class RecyclableScrollRect : ScrollRect
|
||||
{
|
||||
[HideInInspector]
|
||||
public IRecyclableScrollRectDataSource DataSource;
|
||||
|
||||
public bool IsGrid;
|
||||
//Prototype cell can either be a prefab or present as a child to the content(will automatically be disabled in runtime)
|
||||
public RectTransform PrototypeCell;
|
||||
//If true the intiziation happens at Start. Controller must assign the datasource in Awake.
|
||||
//Set to false if self init is not required and use public init API.
|
||||
public bool SelfInitialize = true;
|
||||
|
||||
public enum DirectionType
|
||||
{
|
||||
Vertical,
|
||||
Horizontal
|
||||
}
|
||||
|
||||
public DirectionType Direction;
|
||||
|
||||
//Segments : coloums for vertical and rows for horizontal.
|
||||
public int Segments
|
||||
{
|
||||
set
|
||||
{
|
||||
_segments = Math.Max(value, 2);
|
||||
}
|
||||
get
|
||||
{
|
||||
return _segments;
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
private int _segments;
|
||||
|
||||
private RecyclingSystem _recyclingSystem;
|
||||
private Vector2 _prevAnchoredPos;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
//defafult(built-in) in scroll rect can have both directions enabled, Recyclable scroll rect can be scrolled in only one direction.
|
||||
//setting default as vertical, Initialize() will set this again.
|
||||
vertical = true;
|
||||
horizontal = false;
|
||||
|
||||
if (!Application.isPlaying) return;
|
||||
|
||||
if (SelfInitialize) Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialization when selfInitalize is true. Assumes that data source is set in controller's Awake.
|
||||
/// </summary>
|
||||
private void Initialize()
|
||||
{
|
||||
//Contruct the recycling system.
|
||||
if (Direction == DirectionType.Vertical)
|
||||
{
|
||||
_recyclingSystem = new VerticalRecyclingSystem(PrototypeCell, viewport, content, DataSource, IsGrid, Segments);
|
||||
}
|
||||
else if (Direction == DirectionType.Horizontal)
|
||||
{
|
||||
_recyclingSystem = new HorizontalRecyclingSystem(PrototypeCell, viewport, content, DataSource, IsGrid, Segments);
|
||||
}
|
||||
vertical = Direction == DirectionType.Vertical;
|
||||
horizontal = Direction == DirectionType.Horizontal;
|
||||
|
||||
_prevAnchoredPos = content.anchoredPosition;
|
||||
onValueChanged.RemoveListener(OnValueChangedListener);
|
||||
//Adding listener after pool creation to avoid any unwanted recycling behaviour.(rare scenerio)
|
||||
StartCoroutine(_recyclingSystem.InitCoroutine(() =>
|
||||
onValueChanged.AddListener(OnValueChangedListener)
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// public API for Initializing when datasource is not set in controller's Awake. Make sure selfInitalize is set to false.
|
||||
/// </summary>
|
||||
public void Initialize(IRecyclableScrollRectDataSource dataSource)
|
||||
{
|
||||
DataSource = dataSource;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Added as a listener to the OnValueChanged event of Scroll rect.
|
||||
/// Recycling entry point for recyling systems.
|
||||
/// </summary>
|
||||
/// <param name="direction">scroll direction</param>
|
||||
public void OnValueChangedListener(Vector2 normalizedPos)
|
||||
{
|
||||
Vector2 dir = content.anchoredPosition - _prevAnchoredPos;
|
||||
m_ContentStartPosition += _recyclingSystem.OnValueChangedListener(dir);
|
||||
_prevAnchoredPos = content.anchoredPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Reloads the data. Call this if a new datasource is assigned.
|
||||
/// </summary>
|
||||
public void ReloadData()
|
||||
{
|
||||
ReloadData(DataSource);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded ReloadData with dataSource param
|
||||
///Reloads the data. Call this if a new datasource is assigned.
|
||||
/// </summary>
|
||||
public void ReloadData(IRecyclableScrollRectDataSource dataSource)
|
||||
{
|
||||
if (_recyclingSystem != null)
|
||||
{
|
||||
StopMovement();
|
||||
onValueChanged.RemoveListener(OnValueChangedListener);
|
||||
_recyclingSystem.DataSource = dataSource;
|
||||
StartCoroutine(_recyclingSystem.InitCoroutine(() =>
|
||||
onValueChanged.AddListener(OnValueChangedListener)
|
||||
));
|
||||
_prevAnchoredPos = content.anchoredPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#region Testing
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (_recyclableScrollRect is VerticalRecyclingSystem)
|
||||
{
|
||||
((VerticalRecyclingSystem)_recyclableScrollRect).OnDrawGizmos();
|
||||
}
|
||||
|
||||
if (_recyclableScrollRect is HorizontalRecyclingSystem)
|
||||
{
|
||||
((HorizontalRecyclingSystem)_recyclableScrollRect).OnDrawGizmos();
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 248d9fa993d3e44daa165a75b0063088
|
||||
timeCreated: 1580416764
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 6b7325ceb7a524d43bf38b93ad0c7118, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1b6a61b2a8a958489c9e8598a56feda
|
||||
folderAsset: yes
|
||||
timeCreated: 1598985947
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Recyling system for horizontal type.
|
||||
/// </summary>
|
||||
public class HorizontalRecyclingSystem : RecyclingSystem
|
||||
{
|
||||
//Assigned by constructor
|
||||
private readonly int _rows;
|
||||
|
||||
//Cell dimensions
|
||||
private float _cellWidth, _cellHeight;
|
||||
|
||||
//Pool Generation
|
||||
private List<RectTransform> _cellPool;
|
||||
private List<ICell> _cachedCells;
|
||||
private Bounds _recyclableViewBounds;
|
||||
|
||||
|
||||
//Temps, Flags
|
||||
private readonly Vector3[] _corners = new Vector3[4];
|
||||
private bool _recycling;
|
||||
|
||||
//Trackers
|
||||
private int currentItemCount; //item count corresponding to the datasource.
|
||||
private int leftMostCellIndex, rightMostCellIndex; //Topmost and bottommost cell in the List
|
||||
private int _leftMostCellRow, _RightMostCellRow; // used for recyling in Grid layout. leftmost and rightmost row
|
||||
|
||||
//Cached zero vector
|
||||
private Vector2 zeroVector = Vector2.zero;
|
||||
#region INIT
|
||||
public HorizontalRecyclingSystem(RectTransform prototypeCell, RectTransform viewport, RectTransform content, IRecyclableScrollRectDataSource dataSource, bool isGrid, int rows)
|
||||
{
|
||||
PrototypeCell = prototypeCell;
|
||||
Viewport = viewport;
|
||||
Content = content;
|
||||
DataSource = dataSource;
|
||||
IsGrid = isGrid;
|
||||
_rows = isGrid ? rows : 1;
|
||||
_recyclableViewBounds = new Bounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Corotuine for initiazation.
|
||||
/// Using coroutine for init because few UI stuff requires a frame to update
|
||||
/// </summary>
|
||||
/// <param name="onInitialized">callback when init done</param>
|
||||
/// <returns></returns>
|
||||
public override IEnumerator InitCoroutine(Action onInitialized)
|
||||
{
|
||||
//Setting up container and bounds
|
||||
SetLeftAnchor(Content);
|
||||
Content.anchoredPosition = Vector3.zero;
|
||||
yield return null;
|
||||
SetRecyclingBounds();
|
||||
|
||||
//Cell Poool
|
||||
CreateCellPool();
|
||||
currentItemCount = _cellPool.Count;
|
||||
leftMostCellIndex = 0;
|
||||
rightMostCellIndex = _cellPool.Count - 1;
|
||||
|
||||
//Set content width according to no of coloums
|
||||
int coloums = Mathf.CeilToInt((float)_cellPool.Count / _rows);
|
||||
float contentXSize = coloums * _cellWidth;
|
||||
Content.sizeDelta = new Vector2(contentXSize, Content.sizeDelta.y);
|
||||
SetLeftAnchor(Content);
|
||||
|
||||
if (onInitialized != null) onInitialized();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the uppper and lower bounds for recycling cells.
|
||||
/// </summary>
|
||||
private void SetRecyclingBounds()
|
||||
{
|
||||
Viewport.GetWorldCorners(_corners);
|
||||
float threshHold = RecyclingThreshold * (_corners[2].x - _corners[0].x);
|
||||
_recyclableViewBounds.min = new Vector3(_corners[0].x - threshHold, _corners[0].y);
|
||||
_recyclableViewBounds.max = new Vector3(_corners[2].x + threshHold, _corners[2].y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates cell Pool for recycling, Caches ICells
|
||||
/// </summary>
|
||||
private void CreateCellPool()
|
||||
{
|
||||
//Reseting Pool
|
||||
if (_cellPool != null)
|
||||
{
|
||||
_cellPool.ForEach((RectTransform item) => UnityEngine.Object.Destroy(item.gameObject));
|
||||
_cellPool.Clear();
|
||||
_cachedCells.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedCells = new List<ICell>();
|
||||
_cellPool = new List<RectTransform>();
|
||||
}
|
||||
|
||||
//Set the prototype cell active and set cell anchor as top
|
||||
PrototypeCell.gameObject.SetActive(true);
|
||||
SetLeftAnchor(PrototypeCell);
|
||||
|
||||
//set new cell size according to its aspect ratio
|
||||
_cellHeight = Content.rect.height / _rows;
|
||||
_cellWidth = PrototypeCell.sizeDelta.x / PrototypeCell.sizeDelta.y * _cellHeight;
|
||||
|
||||
//Reset
|
||||
_leftMostCellRow = _RightMostCellRow = 0;
|
||||
|
||||
//Temps
|
||||
float currentPoolCoverage = 0;
|
||||
int poolSize = 0;
|
||||
float posX = 0;
|
||||
float posY = 0;
|
||||
|
||||
//Get the required pool coverage and mininum size for the Cell pool
|
||||
float requriedCoverage = MinPoolCoverage * Viewport.rect.width;
|
||||
int minPoolSize = Math.Min(MinPoolSize, DataSource.GetItemCount());
|
||||
|
||||
//create cells untill the Pool area is covered and pool size is the minimum required
|
||||
while ((poolSize < minPoolSize || currentPoolCoverage < requriedCoverage) && poolSize < DataSource.GetItemCount())
|
||||
{
|
||||
//Instantiate and add to Pool
|
||||
RectTransform item = (UnityEngine.Object.Instantiate(PrototypeCell.gameObject)).GetComponent<RectTransform>();
|
||||
item.name = "Cell";
|
||||
item.sizeDelta = new Vector2(_cellWidth, _cellHeight);
|
||||
_cellPool.Add(item);
|
||||
item.SetParent(Content, false);
|
||||
|
||||
if (IsGrid)
|
||||
{
|
||||
posY = -_RightMostCellRow * _cellHeight;
|
||||
item.anchoredPosition = new Vector2(posX, posY);
|
||||
if (++_RightMostCellRow >= _rows)
|
||||
{
|
||||
_RightMostCellRow = 0;
|
||||
posX += _cellWidth;
|
||||
currentPoolCoverage += item.rect.width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.anchoredPosition = new Vector2(posX, 0);
|
||||
posX = item.anchoredPosition.x + item.rect.width;
|
||||
currentPoolCoverage += item.rect.width;
|
||||
}
|
||||
|
||||
//Setting data for Cell
|
||||
_cachedCells.Add(item.GetComponent<ICell>());
|
||||
DataSource.SetCell(_cachedCells[_cachedCells.Count - 1], poolSize);
|
||||
|
||||
//Update the Pool size
|
||||
poolSize++;
|
||||
}
|
||||
|
||||
if (IsGrid)
|
||||
{
|
||||
_RightMostCellRow = (_RightMostCellRow - 1 + _rows) % _rows;
|
||||
}
|
||||
|
||||
//Deactivate prototype cell if it is not a prefab(i.e it's present in scene)
|
||||
if (PrototypeCell.gameObject.scene.IsValid())
|
||||
{
|
||||
PrototypeCell.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region RECYCLING
|
||||
/// <summary>
|
||||
/// Recyling entry point
|
||||
/// </summary>
|
||||
/// <param name="direction">scroll direction </param>
|
||||
/// <returns></returns>
|
||||
public override Vector2 OnValueChangedListener(Vector2 direction)
|
||||
{
|
||||
if (_recycling || _cellPool == null || _cellPool.Count == 0) return zeroVector;
|
||||
|
||||
//Updating Recyclable view bounds since it can change with resolution changes.
|
||||
SetRecyclingBounds();
|
||||
|
||||
if (direction.x < 0 && _cellPool[rightMostCellIndex].MinX() < _recyclableViewBounds.max.x)
|
||||
{
|
||||
return RecycleLeftToRight();
|
||||
}
|
||||
else if (direction.x > 0 && _cellPool[leftMostCellIndex].MaxX() > _recyclableViewBounds.min.x)
|
||||
{
|
||||
return RecycleRightToleft();
|
||||
}
|
||||
return zeroVector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recycles cells from Left to Right in the List heirarchy
|
||||
/// </summary>
|
||||
private Vector2 RecycleLeftToRight()
|
||||
{
|
||||
_recycling = true;
|
||||
|
||||
int n = 0;
|
||||
float posX = IsGrid ? _cellPool[rightMostCellIndex].anchoredPosition.x : 0;
|
||||
float posY = 0;
|
||||
|
||||
//to determine if content size needs to be updated
|
||||
int additionalColoums = 0;
|
||||
|
||||
//Recycle until cell at left is avaiable and current item count smaller than datasource
|
||||
while (_cellPool[leftMostCellIndex].MaxX() < _recyclableViewBounds.min.x && currentItemCount < DataSource.GetItemCount())
|
||||
{
|
||||
if (IsGrid)
|
||||
{
|
||||
if (++_RightMostCellRow >= _rows)
|
||||
{
|
||||
n++;
|
||||
_RightMostCellRow = 0;
|
||||
posX = _cellPool[rightMostCellIndex].anchoredPosition.x + _cellWidth;
|
||||
additionalColoums++;
|
||||
}
|
||||
|
||||
//Move Left most cell to right
|
||||
posY = -_RightMostCellRow * _cellHeight;
|
||||
_cellPool[leftMostCellIndex].anchoredPosition = new Vector2(posX, posY);
|
||||
|
||||
if (++_leftMostCellRow >= _rows)
|
||||
{
|
||||
_leftMostCellRow = 0;
|
||||
additionalColoums--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move Left most cell to right
|
||||
posX = _cellPool[rightMostCellIndex].anchoredPosition.x + _cellPool[rightMostCellIndex].sizeDelta.x;
|
||||
_cellPool[leftMostCellIndex].anchoredPosition = new Vector2(posX, _cellPool[leftMostCellIndex].anchoredPosition.y);
|
||||
}
|
||||
|
||||
//Cell for row at
|
||||
DataSource.SetCell(_cachedCells[leftMostCellIndex], currentItemCount);
|
||||
|
||||
//set new indices
|
||||
rightMostCellIndex = leftMostCellIndex;
|
||||
leftMostCellIndex = (leftMostCellIndex + 1) % _cellPool.Count;
|
||||
|
||||
currentItemCount++;
|
||||
if (!IsGrid) n++;
|
||||
}
|
||||
|
||||
//Content size adjustment
|
||||
if (IsGrid)
|
||||
{
|
||||
Content.sizeDelta += additionalColoums * Vector2.right * _cellWidth;
|
||||
if (additionalColoums > 0)
|
||||
{
|
||||
n -= additionalColoums;
|
||||
}
|
||||
}
|
||||
|
||||
//Content anchor position adjustment.
|
||||
_cellPool.ForEach((RectTransform cell) => cell.anchoredPosition -= n * Vector2.right * _cellPool[leftMostCellIndex].sizeDelta.x);
|
||||
Content.anchoredPosition += n * Vector2.right * _cellPool[leftMostCellIndex].sizeDelta.x;
|
||||
_recycling = false;
|
||||
return n * Vector2.right * _cellPool[leftMostCellIndex].sizeDelta.x;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recycles cells from Right to Left in the List heirarchy
|
||||
/// </summary>
|
||||
private Vector2 RecycleRightToleft()
|
||||
{
|
||||
_recycling = true;
|
||||
|
||||
int n = 0;
|
||||
float posX = IsGrid ? _cellPool[leftMostCellIndex].anchoredPosition.x : 0;
|
||||
float posY = 0;
|
||||
|
||||
//to determine if content size needs to be updated
|
||||
int additionalColoums = 0;
|
||||
//Recycle until cell at Right end is avaiable and current item count is greater than cellpool size
|
||||
while (_cellPool[rightMostCellIndex].MinX() > _recyclableViewBounds.max.x && currentItemCount > _cellPool.Count)
|
||||
{
|
||||
if (IsGrid)
|
||||
{
|
||||
if (--_leftMostCellRow < 0)
|
||||
{
|
||||
n++;
|
||||
_leftMostCellRow = _rows - 1;
|
||||
posX = _cellPool[leftMostCellIndex].anchoredPosition.x - _cellWidth;
|
||||
additionalColoums++;
|
||||
}
|
||||
|
||||
//Move Right most cell to left
|
||||
posY = -_leftMostCellRow * _cellHeight;
|
||||
_cellPool[rightMostCellIndex].anchoredPosition = new Vector2(posX, posY);
|
||||
|
||||
if (--_RightMostCellRow < 0)
|
||||
{
|
||||
_RightMostCellRow = _rows - 1;
|
||||
additionalColoums--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move Right most cell to left
|
||||
posX = _cellPool[leftMostCellIndex].anchoredPosition.x - _cellPool[leftMostCellIndex].sizeDelta.x;
|
||||
_cellPool[rightMostCellIndex].anchoredPosition = new Vector2(posX, _cellPool[rightMostCellIndex].anchoredPosition.y);
|
||||
n++;
|
||||
}
|
||||
|
||||
currentItemCount--;
|
||||
//Cell for row at
|
||||
DataSource.SetCell(_cachedCells[rightMostCellIndex], currentItemCount - _cellPool.Count);
|
||||
|
||||
//set new indices
|
||||
leftMostCellIndex = rightMostCellIndex;
|
||||
rightMostCellIndex = (rightMostCellIndex - 1 + _cellPool.Count) % _cellPool.Count;
|
||||
}
|
||||
|
||||
//Content size adjustment
|
||||
if (IsGrid)
|
||||
{
|
||||
Content.sizeDelta += additionalColoums * Vector2.right * _cellWidth;
|
||||
if (additionalColoums > 0)
|
||||
{
|
||||
n -= additionalColoums;
|
||||
}
|
||||
}
|
||||
|
||||
//Content anchor position adjustment.
|
||||
_cellPool.ForEach((RectTransform cell) => cell.anchoredPosition += n * Vector2.right * _cellPool[leftMostCellIndex].sizeDelta.x);
|
||||
Content.anchoredPosition -= n * Vector2.right * _cellPool[leftMostCellIndex].sizeDelta.x;
|
||||
_recycling = false;
|
||||
return -n * Vector2.right * _cellPool[leftMostCellIndex].sizeDelta.x;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region HELPERS
|
||||
/// <summary>
|
||||
/// Anchoring cell and content rect transforms to top preset. Makes repositioning easy.
|
||||
/// </summary>
|
||||
/// <param name="rectTransform"></param>
|
||||
private void SetLeftAnchor(RectTransform rectTransform)
|
||||
{
|
||||
//Saving to reapply after anchoring. Width and height changes if anchoring is change.
|
||||
float width = rectTransform.rect.width;
|
||||
float height = rectTransform.rect.height;
|
||||
|
||||
Vector2 pos = IsGrid ? new Vector2(0, 1) : new Vector2(0, 0.5f);
|
||||
|
||||
//Setting top anchor
|
||||
rectTransform.anchorMin = pos;
|
||||
rectTransform.anchorMax = pos;
|
||||
rectTransform.pivot = pos;
|
||||
|
||||
//Reapply size
|
||||
rectTransform.sizeDelta = new Vector2(width, height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TESTING
|
||||
public void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawLine(_recyclableViewBounds.min - new Vector3(0, 2000), _recyclableViewBounds.min + new Vector3(0, 2000));
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(_recyclableViewBounds.max - new Vector3(0, 2000), _recyclableViewBounds.max + new Vector3(0, 2000));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18e7b2b6055ccc94590a39b5401147a8
|
||||
timeCreated: 1595684755
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Absract Class for creating a Recycling system.
|
||||
/// </summary>
|
||||
public abstract class RecyclingSystem
|
||||
{
|
||||
public IRecyclableScrollRectDataSource DataSource;
|
||||
|
||||
protected RectTransform Viewport, Content;
|
||||
protected RectTransform PrototypeCell;
|
||||
protected bool IsGrid;
|
||||
|
||||
protected float MinPoolCoverage = 1.5f; // The recyclable pool must cover (viewPort * _poolCoverage) area.
|
||||
protected int MinPoolSize = 10; // Cell pool must have a min size
|
||||
protected float RecyclingThreshold = .2f; //Threshold for recycling above and below viewport
|
||||
|
||||
public abstract IEnumerator InitCoroutine(System.Action onInitialized = null);
|
||||
|
||||
public abstract Vector2 OnValueChangedListener(Vector2 direction);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52518c8e74351d0469a587c411d4438f
|
||||
timeCreated: 1595684222
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PolyAndCode.UI
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Recyling system for Vertical type.
|
||||
/// </summary>
|
||||
public class VerticalRecyclingSystem : RecyclingSystem
|
||||
{
|
||||
//Assigned by constructor
|
||||
private readonly int _coloumns;
|
||||
|
||||
//Cell dimensions
|
||||
private float _cellWidth, _cellHeight;
|
||||
|
||||
//Pool Generation
|
||||
private List<RectTransform> _cellPool;
|
||||
private List<ICell> _cachedCells;
|
||||
private Bounds _recyclableViewBounds;
|
||||
|
||||
//Temps, Flags
|
||||
private readonly Vector3[] _corners = new Vector3[4];
|
||||
private bool _recycling;
|
||||
|
||||
//Trackers
|
||||
private int currentItemCount; //item count corresponding to the datasource.
|
||||
private int topMostCellIndex, bottomMostCellIndex; //Topmost and bottommost cell in the heirarchy
|
||||
private int _topMostCellColoumn, _bottomMostCellColoumn; // used for recyling in Grid layout. top-most and bottom-most coloumn
|
||||
|
||||
//Cached zero vector
|
||||
private Vector2 zeroVector = Vector2.zero;
|
||||
|
||||
#region INIT
|
||||
public VerticalRecyclingSystem(RectTransform prototypeCell, RectTransform viewport, RectTransform content, IRecyclableScrollRectDataSource dataSource, bool isGrid, int coloumns)
|
||||
{
|
||||
PrototypeCell = prototypeCell;
|
||||
Viewport = viewport;
|
||||
Content = content;
|
||||
DataSource = dataSource;
|
||||
IsGrid = isGrid;
|
||||
_coloumns = isGrid ? coloumns : 1;
|
||||
_recyclableViewBounds = new Bounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Corotuine for initiazation.
|
||||
/// Using coroutine for init because few UI stuff requires a frame to update
|
||||
/// </summary>
|
||||
/// <param name="onInitialized">callback when init done</param>
|
||||
/// <returns></returns>>
|
||||
public override IEnumerator InitCoroutine(System.Action onInitialized)
|
||||
{
|
||||
SetTopAnchor(Content);
|
||||
Content.anchoredPosition = Vector3.zero;
|
||||
yield return null;
|
||||
SetRecyclingBounds();
|
||||
|
||||
//Cell Poool
|
||||
CreateCellPool();
|
||||
currentItemCount = _cellPool.Count;
|
||||
topMostCellIndex = 0;
|
||||
bottomMostCellIndex = _cellPool.Count - 1;
|
||||
|
||||
//Set content height according to no of rows
|
||||
int noOfRows = (int)Mathf.Ceil((float)_cellPool.Count / (float)_coloumns);
|
||||
float contentYSize = noOfRows * _cellHeight;
|
||||
Content.sizeDelta = new Vector2(Content.sizeDelta.x, contentYSize);
|
||||
SetTopAnchor(Content);
|
||||
|
||||
if (onInitialized != null) onInitialized();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the uppper and lower bounds for recycling cells.
|
||||
/// </summary>
|
||||
private void SetRecyclingBounds()
|
||||
{
|
||||
Viewport.GetWorldCorners(_corners);
|
||||
float threshHold = RecyclingThreshold * (_corners[2].y - _corners[0].y);
|
||||
_recyclableViewBounds.min = new Vector3(_corners[0].x, _corners[0].y - threshHold);
|
||||
_recyclableViewBounds.max = new Vector3(_corners[2].x, _corners[2].y + threshHold);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates cell Pool for recycling, Caches ICells
|
||||
/// </summary>
|
||||
private void CreateCellPool()
|
||||
{
|
||||
//Reseting Pool
|
||||
if (_cellPool != null)
|
||||
{
|
||||
_cellPool.ForEach((RectTransform item) => UnityEngine.Object.Destroy(item.gameObject));
|
||||
_cellPool.Clear();
|
||||
_cachedCells.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedCells = new List<ICell>();
|
||||
_cellPool = new List<RectTransform>();
|
||||
}
|
||||
|
||||
//Set the prototype cell active and set cell anchor as top
|
||||
PrototypeCell.gameObject.SetActive(true);
|
||||
if (IsGrid)
|
||||
{
|
||||
SetTopLeftAnchor(PrototypeCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTopAnchor(PrototypeCell);
|
||||
}
|
||||
|
||||
//Reset
|
||||
_topMostCellColoumn = _bottomMostCellColoumn = 0;
|
||||
|
||||
//Temps
|
||||
float currentPoolCoverage = 0;
|
||||
int poolSize = 0;
|
||||
float posX = 0;
|
||||
float posY = 0;
|
||||
|
||||
//set new cell size according to its aspect ratio
|
||||
_cellWidth = Content.rect.width / _coloumns;
|
||||
_cellHeight = PrototypeCell.sizeDelta.y / PrototypeCell.sizeDelta.x * _cellWidth;
|
||||
|
||||
//Get the required pool coverage and mininum size for the Cell pool
|
||||
float requriedCoverage = MinPoolCoverage * Viewport.rect.height;
|
||||
int minPoolSize = Math.Min(MinPoolSize, DataSource.GetItemCount());
|
||||
|
||||
//create cells untill the Pool area is covered and pool size is the minimum required
|
||||
while ((poolSize < minPoolSize || currentPoolCoverage < requriedCoverage) && poolSize < DataSource.GetItemCount())
|
||||
{
|
||||
//Instantiate and add to Pool
|
||||
RectTransform item = (UnityEngine.Object.Instantiate(PrototypeCell.gameObject)).GetComponent<RectTransform>();
|
||||
item.name = "Cell";
|
||||
item.sizeDelta = new Vector2(_cellWidth, _cellHeight);
|
||||
_cellPool.Add(item);
|
||||
item.SetParent(Content, false);
|
||||
|
||||
if (IsGrid)
|
||||
{
|
||||
posX = _bottomMostCellColoumn * _cellWidth;
|
||||
item.anchoredPosition = new Vector2(posX, posY);
|
||||
if (++_bottomMostCellColoumn >= _coloumns)
|
||||
{
|
||||
_bottomMostCellColoumn = 0;
|
||||
posY -= _cellHeight;
|
||||
currentPoolCoverage += item.rect.height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.anchoredPosition = new Vector2(0, posY);
|
||||
posY = item.anchoredPosition.y - item.rect.height;
|
||||
currentPoolCoverage += item.rect.height;
|
||||
}
|
||||
|
||||
//Setting data for Cell
|
||||
_cachedCells.Add(item.GetComponent<ICell>());
|
||||
DataSource.SetCell(_cachedCells[_cachedCells.Count - 1], poolSize);
|
||||
//Update the Pool size
|
||||
poolSize++;
|
||||
}
|
||||
|
||||
//TODO : you alrady have a _currentColoumn varaiable. Why this calculation?????
|
||||
if (IsGrid)
|
||||
{
|
||||
_bottomMostCellColoumn = (_bottomMostCellColoumn - 1 + _coloumns) % _coloumns;
|
||||
}
|
||||
|
||||
//Deactivate prototype cell if it is not a prefab(i.e it's present in scene)
|
||||
if (PrototypeCell.gameObject.scene.IsValid())
|
||||
{
|
||||
PrototypeCell.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region RECYCLING
|
||||
/// <summary>
|
||||
/// Recyling entry point
|
||||
/// </summary>
|
||||
/// <param name="direction">scroll direction </param>
|
||||
/// <returns></returns>
|
||||
public override Vector2 OnValueChangedListener(Vector2 direction)
|
||||
{
|
||||
if (_recycling || _cellPool == null || _cellPool.Count == 0) return zeroVector;
|
||||
|
||||
//Updating Recyclable view bounds since it can change with resolution changes.
|
||||
SetRecyclingBounds();
|
||||
|
||||
if (direction.y > 0 && _cellPool[bottomMostCellIndex].MaxY() > _recyclableViewBounds.min.y)
|
||||
{
|
||||
return RecycleTopToBottom();
|
||||
}
|
||||
else if (direction.y < 0 && _cellPool[topMostCellIndex].MinY() < _recyclableViewBounds.max.y)
|
||||
{
|
||||
return RecycleBottomToTop();
|
||||
}
|
||||
|
||||
return zeroVector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recycles cells from top to bottom in the List heirarchy
|
||||
/// </summary>
|
||||
private Vector2 RecycleTopToBottom()
|
||||
{
|
||||
_recycling = true;
|
||||
|
||||
int n = 0;
|
||||
float posY = IsGrid ? _cellPool[bottomMostCellIndex].anchoredPosition.y : 0;
|
||||
float posX = 0;
|
||||
|
||||
//to determine if content size needs to be updated
|
||||
int additionalRows = 0;
|
||||
//Recycle until cell at Top is avaiable and current item count smaller than datasource
|
||||
while (_cellPool[topMostCellIndex].MinY() > _recyclableViewBounds.max.y && currentItemCount < DataSource.GetItemCount())
|
||||
{
|
||||
if (IsGrid)
|
||||
{
|
||||
if (++_bottomMostCellColoumn >= _coloumns)
|
||||
{
|
||||
n++;
|
||||
_bottomMostCellColoumn = 0;
|
||||
posY = _cellPool[bottomMostCellIndex].anchoredPosition.y - _cellHeight;
|
||||
additionalRows++;
|
||||
}
|
||||
|
||||
//Move top cell to bottom
|
||||
posX = _bottomMostCellColoumn * _cellWidth;
|
||||
_cellPool[topMostCellIndex].anchoredPosition = new Vector2(posX, posY);
|
||||
|
||||
if (++_topMostCellColoumn >= _coloumns)
|
||||
{
|
||||
_topMostCellColoumn = 0;
|
||||
additionalRows--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move top cell to bottom
|
||||
posY = _cellPool[bottomMostCellIndex].anchoredPosition.y - _cellPool[bottomMostCellIndex].sizeDelta.y;
|
||||
_cellPool[topMostCellIndex].anchoredPosition = new Vector2(_cellPool[topMostCellIndex].anchoredPosition.x, posY);
|
||||
}
|
||||
|
||||
//Cell for row at
|
||||
DataSource.SetCell(_cachedCells[topMostCellIndex], currentItemCount);
|
||||
|
||||
//set new indices
|
||||
bottomMostCellIndex = topMostCellIndex;
|
||||
topMostCellIndex = (topMostCellIndex + 1) % _cellPool.Count;
|
||||
|
||||
currentItemCount++;
|
||||
if (!IsGrid) n++;
|
||||
}
|
||||
|
||||
//Content size adjustment
|
||||
if (IsGrid)
|
||||
{
|
||||
Content.sizeDelta += additionalRows * Vector2.up * _cellHeight;
|
||||
//TODO : check if it is supposed to be done only when > 0
|
||||
if (additionalRows > 0)
|
||||
{
|
||||
n -= additionalRows;
|
||||
}
|
||||
}
|
||||
|
||||
//Content anchor position adjustment.
|
||||
_cellPool.ForEach((RectTransform cell) => cell.anchoredPosition += n * Vector2.up * _cellPool[topMostCellIndex].sizeDelta.y);
|
||||
Content.anchoredPosition -= n * Vector2.up * _cellPool[topMostCellIndex].sizeDelta.y;
|
||||
_recycling = false;
|
||||
return -new Vector2(0, n * _cellPool[topMostCellIndex].sizeDelta.y);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recycles cells from bottom to top in the List heirarchy
|
||||
/// </summary>
|
||||
private Vector2 RecycleBottomToTop()
|
||||
{
|
||||
_recycling = true;
|
||||
|
||||
int n = 0;
|
||||
float posY = IsGrid ? _cellPool[topMostCellIndex].anchoredPosition.y : 0;
|
||||
float posX = 0;
|
||||
|
||||
//to determine if content size needs to be updated
|
||||
int additionalRows = 0;
|
||||
//Recycle until cell at bottom is avaiable and current item count is greater than cellpool size
|
||||
while (_cellPool[bottomMostCellIndex].MaxY() < _recyclableViewBounds.min.y && currentItemCount > _cellPool.Count)
|
||||
{
|
||||
|
||||
if (IsGrid)
|
||||
{
|
||||
if (--_topMostCellColoumn < 0)
|
||||
{
|
||||
n++;
|
||||
_topMostCellColoumn = _coloumns - 1;
|
||||
posY = _cellPool[topMostCellIndex].anchoredPosition.y + _cellHeight;
|
||||
additionalRows++;
|
||||
}
|
||||
|
||||
//Move bottom cell to top
|
||||
posX = _topMostCellColoumn * _cellWidth;
|
||||
_cellPool[bottomMostCellIndex].anchoredPosition = new Vector2(posX, posY);
|
||||
|
||||
if (--_bottomMostCellColoumn < 0)
|
||||
{
|
||||
_bottomMostCellColoumn = _coloumns - 1;
|
||||
additionalRows--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move bottom cell to top
|
||||
posY = _cellPool[topMostCellIndex].anchoredPosition.y + _cellPool[topMostCellIndex].sizeDelta.y;
|
||||
_cellPool[bottomMostCellIndex].anchoredPosition = new Vector2(_cellPool[bottomMostCellIndex].anchoredPosition.x, posY);
|
||||
n++;
|
||||
}
|
||||
|
||||
currentItemCount--;
|
||||
|
||||
//Cell for row at
|
||||
DataSource.SetCell(_cachedCells[bottomMostCellIndex], currentItemCount - _cellPool.Count);
|
||||
|
||||
//set new indices
|
||||
topMostCellIndex = bottomMostCellIndex;
|
||||
bottomMostCellIndex = (bottomMostCellIndex - 1 + _cellPool.Count) % _cellPool.Count;
|
||||
}
|
||||
|
||||
if (IsGrid)
|
||||
{
|
||||
Content.sizeDelta += additionalRows * Vector2.up * _cellHeight;
|
||||
//TODOL : check if it is supposed to be done only when > 0
|
||||
if (additionalRows > 0)
|
||||
{
|
||||
n -= additionalRows;
|
||||
}
|
||||
}
|
||||
|
||||
_cellPool.ForEach((RectTransform cell) => cell.anchoredPosition -= n * Vector2.up * _cellPool[topMostCellIndex].sizeDelta.y);
|
||||
Content.anchoredPosition += n * Vector2.up * _cellPool[topMostCellIndex].sizeDelta.y;
|
||||
_recycling = false;
|
||||
return new Vector2(0, n * _cellPool[topMostCellIndex].sizeDelta.y);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region HELPERS
|
||||
/// <summary>
|
||||
/// Anchoring cell and content rect transforms to top preset. Makes repositioning easy.
|
||||
/// </summary>
|
||||
/// <param name="rectTransform"></param>
|
||||
private void SetTopAnchor(RectTransform rectTransform)
|
||||
{
|
||||
//Saving to reapply after anchoring. Width and height changes if anchoring is change.
|
||||
float width = rectTransform.rect.width;
|
||||
float height = rectTransform.rect.height;
|
||||
|
||||
//Setting top anchor
|
||||
rectTransform.anchorMin = new Vector2(0.5f, 1);
|
||||
rectTransform.anchorMax = new Vector2(0.5f, 1);
|
||||
rectTransform.pivot = new Vector2(0.5f, 1);
|
||||
|
||||
//Reapply size
|
||||
rectTransform.sizeDelta = new Vector2(width, height);
|
||||
}
|
||||
|
||||
private void SetTopLeftAnchor(RectTransform rectTransform)
|
||||
{
|
||||
//Saving to reapply after anchoring. Width and height changes if anchoring is change.
|
||||
float width = rectTransform.rect.width;
|
||||
float height = rectTransform.rect.height;
|
||||
|
||||
//Setting top anchor
|
||||
rectTransform.anchorMin = new Vector2(0, 1);
|
||||
rectTransform.anchorMax = new Vector2(0, 1);
|
||||
rectTransform.pivot = new Vector2(0, 1);
|
||||
|
||||
//Reapply size
|
||||
rectTransform.sizeDelta = new Vector2(width, height);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TESTING
|
||||
public void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawLine(_recyclableViewBounds.min - new Vector3(2000, 0), _recyclableViewBounds.min + new Vector3(2000, 0));
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(_recyclableViewBounds.max - new Vector3(2000, 0), _recyclableViewBounds.max + new Vector3(2000, 0));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 360d60b04d7e6a64ab1104c09a3335b0
|
||||
timeCreated: 1595684786
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50cfd769583befc46a5b6c78d9d6f4b8
|
||||
folderAsset: yes
|
||||
timeCreated: 1598985967
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
//MIT License
|
||||
//Copyright (c) 2020 Mohammed Iqubal Hussain
|
||||
//Website : Polyandcode.com
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for Rect Transform
|
||||
/// </summary>
|
||||
public static class UIExtension
|
||||
{
|
||||
public static Vector3[] GetCorners(this RectTransform rectTransform)
|
||||
{
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rectTransform.GetWorldCorners(corners);
|
||||
return corners;
|
||||
}
|
||||
public static float MaxY(this RectTransform rectTransform)
|
||||
{
|
||||
return rectTransform.GetCorners()[1].y;
|
||||
}
|
||||
|
||||
public static float MinY(this RectTransform rectTransform)
|
||||
{
|
||||
return rectTransform.GetCorners()[0].y;
|
||||
}
|
||||
|
||||
public static float MaxX(this RectTransform rectTransform)
|
||||
{
|
||||
return rectTransform.GetCorners()[2].x;
|
||||
}
|
||||
|
||||
public static float MinX(this RectTransform rectTransform)
|
||||
{
|
||||
return rectTransform.GetCorners()[0].x;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12216d152b4b943e88a3d40b029c3e3e
|
||||
timeCreated: 1580410439
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user