├── .gitignore ├── Assets ├── Scripts.meta └── Scripts │ ├── Fragment.meta │ └── Fragment │ ├── BaseBehaviour.cs │ ├── BaseBehaviour.cs.meta │ ├── Fragment.cs │ ├── Fragment.cs.meta │ ├── FragmentAnimator.cs │ ├── FragmentAnimator.cs.meta │ ├── FragmentManager.cs │ ├── FragmentManager.cs.meta │ ├── FragmentRayCastManager.cs │ ├── FragmentRayCastManager.cs.meta │ ├── IFragmentAnimator.cs │ ├── IFragmentAnimator.cs.meta │ ├── InputEventHandler.cs │ ├── InputEventHandler.cs.meta │ ├── Utils.cs │ └── Utils.cs.meta ├── LICENSE.txt ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityAdsSettings.asset └── UnityConnectSettings.asset └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Autogenerated VS/MD solution and project files 9 | ExportedObj/ 10 | *.csproj 11 | *.unityproj 12 | *.sln 13 | *.suo 14 | *.tmp 15 | *.user 16 | *.userprefs 17 | *.pidb 18 | *.booproj 19 | *.svd 20 | 21 | 22 | # Unity3D generated meta files 23 | *.pidb.meta 24 | 25 | # Unity3D Generated File On Crash Reports 26 | sysinfo.txt 27 | 28 | # Builds 29 | *.apk 30 | *.unitypackage 31 | -------------------------------------------------------------------------------- /Assets/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17105df350ad24bf48280801cca46457 3 | folderAsset: yes 4 | timeCreated: 1490348035 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0e6f8b239ade434cb4188b3b29d436c 3 | folderAsset: yes 4 | timeCreated: 1490522210 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/BaseBehaviour.cs: -------------------------------------------------------------------------------- 1 | // hcq 2017/3/26 2 | using UnityEngine; 3 | 4 | namespace UnityFragment 5 | { 6 | public class BaseBehaviour : MonoBehaviour 7 | { 8 | FragmentRayCastManager raycastManager; 9 | GameObject canvas; 10 | 11 | protected internal virtual GameObject GetCanvas() 12 | { 13 | if (canvas == null) 14 | { 15 | canvas = Utils.GetCanvas(); 16 | } 17 | 18 | return canvas; 19 | } 20 | 21 | protected internal FragmentRayCastManager GetRayCastManager() 22 | { 23 | if (raycastManager == null) 24 | { 25 | raycastManager = FragmentRayCastManager.GetInstance(GetCanvas()); 26 | } 27 | 28 | return raycastManager; 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/BaseBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2513df047cb984970b838607869557c1 3 | timeCreated: 1490512890 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/Fragment.cs: -------------------------------------------------------------------------------- 1 | // Created by hcq 2 | using UnityEngine; 3 | 4 | namespace UnityFragment 5 | { 6 | [DisallowMultipleComponent] 7 | public abstract class Fragment : BaseBehaviour 8 | { 9 | #region life cycle 10 | 11 | //子类重载 进栈时回调 为了区分OnEnable时不同逻辑 12 | public virtual void OnEnterStack() 13 | { 14 | } 15 | 16 | //子类重载 出栈时回调 为了区分OnDisable时不同逻辑 17 | public virtual void OnExitStack() 18 | { 19 | } 20 | 21 | //子类重载 通过intent启动fragment时回调 22 | public virtual void OnIntent(string extra) 23 | { 24 | } 25 | 26 | #region animation 27 | 28 | //返回动画时长 29 | protected internal virtual float DoExitAnimation() 30 | { 31 | return 0f; 32 | } 33 | 34 | //返回动画时长 35 | protected internal virtual float DoEnterAnimation() 36 | { 37 | return 0f; 38 | } 39 | 40 | //按返回键是否执行动画 41 | protected internal virtual bool IsDoAnimationOnBackPressed() 42 | { 43 | return true; 44 | } 45 | 46 | #endregion 47 | 48 | protected internal virtual void OnDynamicInstantiated() 49 | { 50 | 51 | } 52 | 53 | #endregion 54 | 55 | #region input event 56 | 57 | //子类重载 58 | public virtual bool OnBackPressed() 59 | { 60 | return false; 61 | } 62 | 63 | //子类重载 64 | public virtual bool OnMenuPressed() 65 | { 66 | return false; 67 | } 68 | 69 | //子类重载 70 | public virtual bool OnHomePressed() 71 | { 72 | return false; 73 | } 74 | 75 | //子类需要处理长按事件时重载 76 | public virtual bool OnLongBackPressed() 77 | { 78 | return false; 79 | } 80 | 81 | #endregion 82 | 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/Fragment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd723735c54754a1597ea7e6767c71af 3 | timeCreated: 1490348066 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/FragmentAnimator.cs: -------------------------------------------------------------------------------- 1 | // hcq 2016/12/7 2 | using System; 3 | using UnityEngine; 4 | 5 | namespace UnityFragment 6 | { 7 | [DisallowMultipleComponent] 8 | public class FragmentAnimator : BaseBehaviour, IFragmentAnimator 9 | { 10 | //应用退出动画 11 | public void DoApplicationQuitAnimation(Action onAnimationEnd = null) 12 | { 13 | } 14 | 15 | //fragment切换动画 16 | public void DoAnimation(Fragment enterFragment, Fragment exitFragment, Action onAnimationEnd = null) 17 | { 18 | float exitDuration = 0, enterDuration = 0; 19 | 20 | if (exitFragment != null) 21 | { 22 | exitDuration = exitFragment.DoExitAnimation(); 23 | } 24 | if (enterFragment != null) 25 | { 26 | enterDuration = enterFragment.DoEnterAnimation(); 27 | } 28 | 29 | float animationDuration = Math.Max(exitDuration, enterDuration); 30 | 31 | if (animationDuration > 0) 32 | { 33 | GetRayCastManager().Block(animationDuration, () => 34 | { 35 | if (onAnimationEnd != null) 36 | { 37 | onAnimationEnd(); 38 | } 39 | }); 40 | } 41 | else 42 | { 43 | if (onAnimationEnd != null) 44 | { 45 | onAnimationEnd(); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/FragmentAnimator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 28d6c173d49844cddbd73e4b32ad55d7 3 | timeCreated: 1490348064 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/FragmentManager.cs: -------------------------------------------------------------------------------- 1 | // Created by hcq 2 | //这个类中的函数保证一个页面中只会被调一次 所以应该与根物体绑定 3 | using UnityEngine; 4 | using System.Collections.Generic; 5 | using System; 6 | 7 | namespace UnityFragment 8 | { 9 | [DisallowMultipleComponent] 10 | public sealed class FragmentManager : BaseBehaviour 11 | { 12 | const string UNINSTANTIATE_FRAGMENT_TAG = "UnInstantiateFragment"; 13 | 14 | public delegate bool OnBeforeApplicationQuitDelegate(Action ApplicationQuitAction); 15 | 16 | //动态加载的fragment prefab 17 | public GameObject[] dynamicFragmentPrefabs; 18 | 19 | public IFragmentAnimator fragmentAnimator; 20 | 21 | //fragment显示栈 22 | readonly List fragmentStack = new List(); 23 | //所有的fragment 24 | List allFragments; 25 | 26 | InputEventHandler inputEventHandler; 27 | 28 | //应用退出前的回调 可以用于满足应用退出时的特殊需求 29 | OnBeforeApplicationQuitDelegate OnBeforeApplicationQuit; 30 | 31 | #region 生命周期 32 | 33 | public void Awake() 34 | { 35 | //已经挂在scene中的fragment 36 | Fragment[] fragmentsInScene = GetComponentsInChildren(true); 37 | 38 | FillAllFragments(fragmentsInScene); 39 | FirstFragmentEnterStack(fragmentsInScene); 40 | 41 | InitInputEvent(); 42 | 43 | } 44 | 45 | public void Update() 46 | { 47 | inputEventHandler.DispatchEvent(); 48 | } 49 | 50 | public void OnDestroy() 51 | { 52 | ClearFragments(); 53 | } 54 | 55 | #endregion 56 | 57 | public static FragmentManager GetInstance(GameObject canvas) 58 | { 59 | return Utils.GetComponent(canvas); 60 | } 61 | 62 | public static FragmentManager GetInstance() 63 | { 64 | return GetInstance(Utils.GetCanvas()); 65 | } 66 | 67 | //初始化触控 68 | void InitInputEvent() 69 | { 70 | inputEventHandler = new InputEventHandler(); 71 | inputEventHandler.SetBackPressedListener(HandleBackPressed); 72 | inputEventHandler.SetMenuPressedListener(HandleMenuPressed); 73 | inputEventHandler.SetHomePressedListener(HandleHomePressed); 74 | inputEventHandler.SetLongBackPressListener(HandleLongBackPress); 75 | } 76 | 77 | void FillAllFragments(Fragment[] fragmentsInScene) 78 | { 79 | allFragments = new List(fragmentsInScene); 80 | 81 | if (!Utils.IsCollectionEmpty(dynamicFragmentPrefabs)) 82 | { 83 | for (int i = 0; i < dynamicFragmentPrefabs.Length; i++) 84 | { 85 | GameObject prefab = dynamicFragmentPrefabs[i]; 86 | Fragment fragment = prefab.GetComponent(); 87 | if (fragment != null) 88 | { 89 | if (!allFragments.Contains(fragment)) 90 | { 91 | fragment.tag = UNINSTANTIATE_FRAGMENT_TAG; 92 | allFragments.Add(fragment); 93 | } 94 | } 95 | } 96 | } 97 | 98 | //Debug.Log("hcq fragment " + allFragments.Count); 99 | //foreach (Fragment fragment in allFragments) 100 | //{ 101 | // Debug.Log("hcq fragment " + fragment.name); 102 | //} 103 | } 104 | 105 | //把第一个界面放入栈里 106 | void FirstFragmentEnterStack(Fragment[] fragmentsInScene) 107 | { 108 | for (int i = 0; i < fragmentsInScene.Length; i++) 109 | { 110 | Fragment fragment = fragmentsInScene[i]; 111 | //找第一个物体可见的fragment 112 | if (fragment.gameObject.activeSelf && fragment.enabled) 113 | { 114 | //没有指定某个需要启动的fragment 115 | FragmentEnterStack(fragment); 116 | return; 117 | } 118 | } 119 | } 120 | 121 | void FragmentEnterStack(Fragment fragment) 122 | { 123 | fragmentStack.Add(fragment); 124 | fragment.OnEnterStack(); 125 | } 126 | 127 | void FragmentExitStack(Fragment deleteFragment, bool isCallBack = true) 128 | { 129 | //从后面删 避免存在相同引用的fragment删除了前面的 130 | for (int i = fragmentStack.Count - 1; i >= 0; i--) 131 | { 132 | Fragment fragment = fragmentStack[i]; 133 | if (fragment.Equals(deleteFragment)) 134 | { 135 | fragmentStack.RemoveAt(i); 136 | if (isCallBack) 137 | { 138 | fragment.OnExitStack(); 139 | } 140 | break; 141 | } 142 | } 143 | } 144 | 145 | void ClearTopFragments(Fragment moveToTopFragment) 146 | { 147 | for (int i = fragmentStack.Count - 1; i >= 0; i--) 148 | { 149 | Fragment fragment = fragmentStack[i]; 150 | if (!fragment.Equals(moveToTopFragment)) 151 | { 152 | fragmentStack.RemoveAt(i); 153 | fragment.OnExitStack(); 154 | } 155 | else 156 | { 157 | break; 158 | } 159 | } 160 | } 161 | 162 | void ClearFragments() 163 | { 164 | //在foreach循环中修改元素会抛异常 所以必须用for循环 但正序for循环会导致只删除一般元素 所以这里必须用倒序循环 165 | for (int i = fragmentStack.Count - 1; i >= 0; i--) 166 | { 167 | Fragment fragment = fragmentStack[i]; 168 | fragmentStack.RemoveAt(i); 169 | fragment.OnExitStack(); 170 | } 171 | } 172 | 173 | public Fragment GetTopFragment() 174 | { 175 | //foreach (Fragment fragment in fragmentStack) 176 | //{ 177 | // Debug.Log("hcq fragmentStack " + fragment.name); 178 | //} 179 | //Debug.Log("hcq fragmentStack end -------"); 180 | return !Utils.IsCollectionEmpty(fragmentStack) ? fragmentStack[fragmentStack.Count - 1] : null; 181 | } 182 | 183 | public Fragment GetPreviousFragment() 184 | { 185 | Fragment preFragment = null; 186 | int preIndex = fragmentStack.Count - 2; 187 | if (preIndex >= 0) 188 | { 189 | preFragment = fragmentStack[preIndex]; 190 | } 191 | 192 | return preFragment; 193 | } 194 | 195 | public int GetFragmentCountInStack() 196 | { 197 | return Utils.IsCollectionEmpty(fragmentStack) ? 0 : fragmentStack.Count; 198 | } 199 | 200 | #region 处理按键操作 201 | 202 | public bool HandleBackPressed() 203 | { 204 | // 点击事件被禁用时 返回键事件也要被禁用 205 | if (GetRayCastManager().isBlocking) 206 | { 207 | return true; 208 | } 209 | 210 | Fragment activeFragment = GetTopFragment(); 211 | bool isConsumed = activeFragment != null && activeFragment.OnBackPressed(); 212 | 213 | if (!isConsumed) 214 | { 215 | Fragment previousFragment = GetPreviousFragment(); 216 | 217 | if (previousFragment == null) 218 | { 219 | //应用退出 220 | ApplicationQuit(); 221 | } 222 | else 223 | { 224 | //fragment返回 225 | Exit(activeFragment.IsDoAnimationOnBackPressed()); 226 | } 227 | } 228 | 229 | return isConsumed; 230 | } 231 | 232 | public FragmentManager SetOnBeforeApplicationQuit(OnBeforeApplicationQuitDelegate callback) 233 | { 234 | OnBeforeApplicationQuit = callback; 235 | return this; 236 | } 237 | 238 | void ApplicationQuit() 239 | { 240 | Action ApplicationQuitAction = delegate 241 | { 242 | GetFragmentAnimator().DoApplicationQuitAnimation(Application.Quit); 243 | }; 244 | 245 | bool isConsumed = false; 246 | 247 | if (OnBeforeApplicationQuit != null) 248 | { 249 | isConsumed = OnBeforeApplicationQuit(ApplicationQuitAction); 250 | } 251 | 252 | if (!isConsumed) 253 | { 254 | ApplicationQuitAction(); 255 | } 256 | } 257 | 258 | bool HandleLongBackPress() 259 | { 260 | Fragment activeFragment = GetTopFragment(); 261 | return activeFragment != null && activeFragment.OnLongBackPressed(); 262 | } 263 | 264 | bool HandleMenuPressed() 265 | { 266 | Fragment activeFragment = GetTopFragment(); 267 | return activeFragment != null && activeFragment.OnMenuPressed(); 268 | 269 | } 270 | 271 | bool HandleHomePressed() 272 | { 273 | Fragment activeFragment = GetTopFragment(); 274 | return activeFragment != null && activeFragment.OnHomePressed(); 275 | 276 | } 277 | 278 | #endregion 279 | 280 | public Fragment FindFragmentByName(string gameObjectName) 281 | { 282 | for (int i = 0; i < allFragments.Count; i++) 283 | { 284 | Fragment fragment = allFragments[i]; 285 | if (string.Equals(fragment.gameObject.name, gameObjectName)) 286 | { 287 | return fragment; 288 | } 289 | } 290 | 291 | return null; 292 | } 293 | 294 | #region 显示 295 | 296 | public void Enter(ref Fragment nextFragment) 297 | { 298 | Enter(ref nextFragment, true); 299 | } 300 | 301 | public void Enter(ref Fragment nextFragment, bool isDoAnimation) 302 | { 303 | FragmentIntent intent = new FragmentIntent(); 304 | intent.isDoAnimation = isDoAnimation; 305 | 306 | Enter(ref nextFragment, intent); 307 | } 308 | 309 | public void Enter(ref Fragment nextFragment, FragmentIntent intent) 310 | { 311 | Fragment activeFragment = GetTopFragment(); 312 | 313 | //先要显示下一个 让界面加载出来 再显示动画 314 | switch (intent.launchMode) 315 | { 316 | case FragmentIntent.FLAG_CLEAR_TOP: 317 | 318 | bool isInStack = fragmentStack.Contains(nextFragment); 319 | if (isInStack) 320 | { 321 | ClearTopFragments(nextFragment); 322 | } 323 | 324 | //不在显示栈中要进栈 325 | EnterSpecificFragment(ref nextFragment, !isInStack); 326 | 327 | break; 328 | case FragmentIntent.FLAG_NEW_INSTANCE: 329 | 330 | EnterSpecificFragment(ref nextFragment, true); 331 | 332 | break; 333 | case FragmentIntent.FLAG_SINGLE_INSTANCE: 334 | 335 | isInStack = fragmentStack.Contains(nextFragment); 336 | if (isInStack) 337 | { 338 | FragmentExitStack(nextFragment, false); 339 | } 340 | 341 | EnterSpecificFragment(ref nextFragment, true); 342 | 343 | break; 344 | } 345 | 346 | nextFragment.OnIntent(intent.extra); 347 | 348 | if (intent.isDoAnimation) 349 | { 350 | GetFragmentAnimator().DoAnimation(nextFragment, activeFragment, () => 351 | { 352 | ExitSpecificFragment(activeFragment, false); 353 | }); 354 | } 355 | else 356 | { 357 | ExitSpecificFragment(activeFragment, false); 358 | } 359 | } 360 | 361 | //显示某一个 362 | void EnterSpecificFragment(ref Fragment specificFragment, bool addToStack) 363 | { 364 | if (specificFragment != null) 365 | { 366 | if (specificFragment.transform.parent == null) 367 | { 368 | if (specificFragment.CompareTag(UNINSTANTIATE_FRAGMENT_TAG)) 369 | { 370 | InstantiateFragment(ref specificFragment); 371 | } 372 | 373 | specificFragment.transform.SetParent(transform, false); 374 | } 375 | 376 | if (addToStack) 377 | { 378 | FragmentEnterStack(specificFragment); 379 | } 380 | 381 | if (!specificFragment.transform.parent.gameObject.activeInHierarchy) 382 | { 383 | specificFragment.transform.parent.gameObject.SetActive(true); 384 | } 385 | 386 | if (!specificFragment.gameObject.activeInHierarchy) 387 | { 388 | specificFragment.gameObject.SetActive(true); 389 | } 390 | 391 | if (!specificFragment.isActiveAndEnabled) 392 | { 393 | specificFragment.enabled = true; 394 | } 395 | } 396 | } 397 | 398 | void InstantiateFragment(ref Fragment specificFragment) 399 | { 400 | GameObject obj = Instantiate(specificFragment.gameObject); 401 | obj.name = specificFragment.gameObject.name; 402 | 403 | //销毁prefab 404 | if (allFragments.Contains(specificFragment)) 405 | { 406 | allFragments.Remove(specificFragment); 407 | } 408 | Destroy(specificFragment.gameObject); 409 | 410 | //实例化 411 | specificFragment = obj.GetComponent(); 412 | specificFragment.tag = "Untagged";//unity默认自带的tag 413 | if (!allFragments.Contains(specificFragment)) 414 | { 415 | allFragments.Add(specificFragment); 416 | } 417 | 418 | Fragment[] childFragments = specificFragment.GetComponentsInChildren(true); 419 | for (int i = 0; i < childFragments.Length; i++) 420 | { 421 | Fragment childFragment = childFragments[i]; 422 | if (!allFragments.Contains(childFragment)) 423 | { 424 | allFragments.Add(childFragment); 425 | } 426 | } 427 | 428 | specificFragment.OnDynamicInstantiated(); 429 | 430 | //Debug.Log("hcq InstantiateSpecificFragment " + allFragments.Count); 431 | //foreach (Fragment fragment in allFragments) 432 | //{ 433 | // Debug.Log("hcq InstantiateSpecificFragment " + fragment.name); 434 | //} 435 | } 436 | 437 | public Fragment Enter(string gameObjectName) 438 | { 439 | return Enter(gameObjectName, true); 440 | } 441 | 442 | public Fragment Enter(string gameObjectName, bool isDoAnimation) 443 | { 444 | FragmentIntent intent = new FragmentIntent(); 445 | intent.isDoAnimation = isDoAnimation; 446 | 447 | return Enter(gameObjectName, intent); 448 | } 449 | 450 | public Fragment Enter(string gameObjectName, FragmentIntent intent) 451 | { 452 | Fragment nextFragment = FindFragmentByName(gameObjectName); 453 | Enter(ref nextFragment, intent); 454 | 455 | return nextFragment; 456 | } 457 | 458 | #endregion 459 | 460 | #region 隐藏 461 | 462 | public void Exit(Fragment specificFragment) 463 | { 464 | Exit(specificFragment, true); 465 | } 466 | 467 | public void Exit(Fragment specificFragment, bool isDoAnimation) 468 | { 469 | Fragment previousFragment = GetPreviousFragment(); 470 | 471 | //先要显示上一个 让界面加载出来 再显示动画 472 | EnterSpecificFragment(ref previousFragment, false); 473 | 474 | if (isDoAnimation) 475 | { 476 | GetFragmentAnimator().DoAnimation(previousFragment, specificFragment, () => 477 | { 478 | ExitSpecificFragment(specificFragment, true); 479 | }); 480 | } 481 | else 482 | { 483 | ExitSpecificFragment(specificFragment, true); 484 | } 485 | 486 | } 487 | 488 | //隐藏某一个 489 | void ExitSpecificFragment(Fragment specificFragment, bool removeFromStack) 490 | { 491 | if (specificFragment != null) 492 | { 493 | if (specificFragment.gameObject.activeInHierarchy) 494 | { 495 | specificFragment.gameObject.SetActive(false); 496 | } 497 | 498 | if (specificFragment.isActiveAndEnabled) 499 | { 500 | specificFragment.enabled = false; 501 | } 502 | 503 | if (removeFromStack) 504 | { 505 | FragmentExitStack(specificFragment); 506 | } 507 | } 508 | } 509 | 510 | public Fragment Exit(string gameObjectName) 511 | { 512 | return Exit(gameObjectName, true); 513 | } 514 | 515 | public Fragment Exit(string gameObjectName, bool isDoAnimation) 516 | { 517 | Fragment oldFragment = FindFragmentByName(gameObjectName); 518 | Exit(oldFragment, isDoAnimation); 519 | 520 | return oldFragment; 521 | } 522 | 523 | public Fragment Exit() 524 | { 525 | return Exit(true); 526 | } 527 | 528 | public Fragment Exit(bool isDoAnimation) 529 | { 530 | //隐藏当前的 531 | Fragment activeFragment = GetTopFragment(); 532 | Exit(activeFragment, isDoAnimation); 533 | 534 | return activeFragment; 535 | } 536 | 537 | #endregion 538 | 539 | public IFragmentAnimator GetFragmentAnimator() 540 | { 541 | if (fragmentAnimator == null) 542 | { 543 | GameObject canvas = GetCanvas(); 544 | fragmentAnimator = canvas.GetComponent(); 545 | 546 | if (fragmentAnimator == null) 547 | { 548 | fragmentAnimator = canvas.AddComponent(); 549 | } 550 | } 551 | 552 | return fragmentAnimator; 553 | } 554 | 555 | } 556 | } 557 | 558 | namespace Fragments 559 | { 560 | public class FragmentIntent 561 | { 562 | public const int FLAG_NEW_INSTANCE = 1; 563 | public const int FLAG_CLEAR_TOP = 2; 564 | public const int FLAG_SINGLE_INSTANCE = 3; 565 | 566 | public string fragmentName; 567 | public string extra; 568 | 569 | public int launchMode = FLAG_NEW_INSTANCE; 570 | public bool isDoAnimation; 571 | } 572 | } -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/FragmentManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62ed5254fc5a84d8dba84d4897f3d1bd 3 | timeCreated: 1490348064 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/FragmentRayCastManager.cs: -------------------------------------------------------------------------------- 1 | // hcq 2017/1/16 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | using System; 6 | 7 | namespace UnityFragment 8 | { 9 | [DisallowMultipleComponent] 10 | public class FragmentRayCastManager : BaseBehaviour 11 | { 12 | public bool isBlocking { get { return !Utils.IsCollectionEmpty(blockingCoroutines); } } 13 | 14 | // 用来屏蔽全部事件, 挂载到 Canvas 上 15 | CanvasGroup blockRaycastsCanvasGroup; 16 | readonly Dictionary blockingCoroutines = new Dictionary(); 17 | 18 | public static FragmentRayCastManager GetInstance() 19 | { 20 | return GetInstance(Utils.GetCanvas()); 21 | } 22 | 23 | public static FragmentRayCastManager GetInstance(GameObject canvas) 24 | { 25 | return Utils.GetComponent(canvas); 26 | } 27 | 28 | //动画期间需要屏蔽焦点事件 防止用户误点 29 | public void Block(float blockDurationForSeconds, Action onBlockEnd = null) 30 | { 31 | if (gameObject.activeInHierarchy) 32 | { 33 | long timeStamp = Utils.GetTimeStamp(); 34 | 35 | Coroutine blockRaycastsCoroutine = StartCoroutine(BlockCoroutine(blockDurationForSeconds, onBlockEnd, timeStamp)); 36 | blockingCoroutines.Add(timeStamp, blockRaycastsCoroutine); 37 | } 38 | } 39 | 40 | IEnumerator BlockCoroutine(float blockDurationForSeconds, Action onBlockEnd, long timeStamp) 41 | { 42 | // init fullScreenCanvasGroup 43 | if (blockRaycastsCanvasGroup == null) 44 | { 45 | GameObject canvas = GetCanvas(); 46 | if (canvas != null) 47 | { 48 | blockRaycastsCanvasGroup = canvas.GetComponent(); 49 | if (blockRaycastsCanvasGroup == null) 50 | { 51 | blockRaycastsCanvasGroup = canvas.AddComponent(); 52 | } 53 | } 54 | } 55 | 56 | // blockRaycastsCanvasGroup 仍然有可能为空, 比如界面的 Canvas 不存在, 被更名 等 57 | if (blockRaycastsCanvasGroup != null) 58 | { 59 | blockRaycastsCanvasGroup.blocksRaycasts = false; 60 | } 61 | 62 | //异步等待 63 | yield return new WaitForSeconds(blockDurationForSeconds); 64 | 65 | if (blockRaycastsCanvasGroup != null) 66 | { 67 | blockRaycastsCanvasGroup.blocksRaycasts = true; 68 | } 69 | 70 | if (blockingCoroutines.ContainsKey(timeStamp)) 71 | { 72 | blockingCoroutines.Remove(timeStamp); 73 | } 74 | 75 | if (onBlockEnd != null) 76 | { 77 | onBlockEnd(); 78 | } 79 | } 80 | 81 | protected void OnDisable() 82 | { 83 | if (!Utils.IsCollectionEmpty(blockingCoroutines)) 84 | { 85 | foreach (Coroutine co in blockingCoroutines.Values) 86 | { 87 | StopCoroutine(co); 88 | } 89 | 90 | blockingCoroutines.Clear(); 91 | 92 | } 93 | 94 | //恢复状态 95 | if (blockRaycastsCanvasGroup != null) 96 | { 97 | blockRaycastsCanvasGroup.blocksRaycasts = true; 98 | } 99 | 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/FragmentRayCastManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b52a46399b83746fab5769e41a7cc36e 3 | timeCreated: 1490511866 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/IFragmentAnimator.cs: -------------------------------------------------------------------------------- 1 | // hcq 2017/3/26 2 | using System; 3 | 4 | namespace UnityFragment 5 | { 6 | public interface IFragmentAnimator 7 | { 8 | void DoApplicationQuitAnimation(Action onAnimationEnd = null); 9 | 10 | void DoAnimation(Fragment enterFragment, Fragment exitFragment, Action onAnimationEnd = null); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/IFragmentAnimator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87273687c22ff4688a90d61a46deedfc 3 | timeCreated: 1490511675 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/InputEventHandler.cs: -------------------------------------------------------------------------------- 1 | // Created by hcq 2 | using UnityEngine; 3 | 4 | namespace UnityFragment 5 | { 6 | public class InputEventHandler 7 | { 8 | #region delegate 9 | 10 | public delegate bool OnBackPressedDelegate(); 11 | 12 | public delegate bool OnMenuPressedDelegate(); 13 | 14 | public delegate bool OnHomePressedDelegate(); 15 | 16 | public delegate bool OnLongBackPressedDelegate(); 17 | 18 | #endregion 19 | 20 | #region _listener 21 | 22 | OnLongBackPressedDelegate longBackPressListener; 23 | OnBackPressedDelegate backPressedListener; 24 | OnMenuPressedDelegate menuPressedListener; 25 | OnHomePressedDelegate homePressedListener; 26 | 27 | #endregion 28 | 29 | readonly int LONG_PRESS_DURATION = 1; 30 | // unit is second 31 | float keydownTime; 32 | 33 | #region set listeners 34 | public void SetLongBackPressListener(OnLongBackPressedDelegate listener) 35 | { 36 | longBackPressListener = listener; 37 | } 38 | 39 | public void SetBackPressedListener(OnBackPressedDelegate listener) 40 | { 41 | backPressedListener = listener; 42 | } 43 | 44 | public void SetMenuPressedListener(OnMenuPressedDelegate listener) 45 | { 46 | menuPressedListener = listener; 47 | } 48 | 49 | public void SetHomePressedListener(OnHomePressedDelegate listener) 50 | { 51 | homePressedListener = listener; 52 | } 53 | 54 | #endregion 55 | 56 | public void DispatchEvent() 57 | { 58 | if (Input.GetKeyUp(KeyCode.Escape)) 59 | { 60 | // 松开返回键 61 | if (Time.timeSinceLevelLoad - keydownTime >= LONG_PRESS_DURATION) 62 | { 63 | if (longBackPressListener != null) 64 | { 65 | longBackPressListener(); 66 | } 67 | } 68 | else 69 | { 70 | if (null != backPressedListener) 71 | { 72 | backPressedListener(); 73 | } 74 | } 75 | } 76 | else if (Input.GetKeyDown(KeyCode.Escape)) 77 | { 78 | //按了返回键 79 | keydownTime = Time.timeSinceLevelLoad; 80 | } 81 | else if (Input.GetKeyDown(KeyCode.Menu)) 82 | { 83 | //按了菜单键 84 | if (menuPressedListener != null) 85 | { 86 | menuPressedListener(); 87 | } 88 | } 89 | else if (Input.GetKeyDown(KeyCode.Home)) 90 | { 91 | //按了home键 92 | if (homePressedListener != null) 93 | { 94 | homePressedListener(); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/InputEventHandler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a81bd15fc369c4e13aafa149d7160d68 3 | timeCreated: 1490348413 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/Utils.cs: -------------------------------------------------------------------------------- 1 | // hcq 2017/3/26 2 | using System.Collections; 3 | using UnityEngine; 4 | using UnityEngine.SceneManagement; 5 | using System; 6 | 7 | namespace UnityFragment 8 | { 9 | public static class Utils 10 | { 11 | public static bool IsCollectionEmpty(ICollection collection) 12 | { 13 | return collection == null || collection.Count == 0; 14 | } 15 | 16 | public static GameObject GetCanvas() 17 | { 18 | GameObject canvasGo = GameObject.Find("Canvas"); 19 | 20 | if (canvasGo == null) 21 | { 22 | GameObject[] rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects(); 23 | for (int i = 0; i < rootGameObjects.Length; i++) 24 | { 25 | GameObject rootGameObject = rootGameObjects[i]; 26 | Canvas canvas = rootGameObject.GetComponent(); 27 | if (canvas != null) 28 | { 29 | canvasGo = canvas.gameObject; 30 | break; 31 | } 32 | } 33 | } 34 | 35 | return canvasGo; 36 | } 37 | 38 | public static T GetComponent(GameObject obj) where T : Component 39 | { 40 | T component = obj.GetComponent(); 41 | 42 | if (component == null) 43 | { 44 | component = obj.AddComponent(); 45 | } 46 | 47 | return component; 48 | } 49 | 50 | //获取当前时间戳 51 | public static long GetTimeStamp() 52 | { 53 | DateTime now = TimeZone.CurrentTimeZone.ToLocalTime(DateTime.Now); 54 | DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); 55 | TimeSpan elapsedTime = now - dtStart; 56 | return (long)elapsedTime.TotalMilliseconds; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Assets/Scripts/Fragment/Utils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dad003170a8f14a5f90a9d7959e35bec 3 | timeCreated: 1490512890 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hcq 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.3.4f1 2 | m_StandardAssetsVersion: 0 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcq0618/Unity-Fragment/34e694f527a1f51f77d590aecc1a945abce1a154/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity-Fragment 2 | 用于UGUI界面间的跳转,类似Android中的Fragment 3 | Use for switching UGUI pages, just like Fragment in Android. 4 | 5 | build in Unity 5.3.4f 6 | 7 | 8 | 9 | ## 用法 10 | 1.FragmentManager挂在Canvas上 11 | 12 | FragmentManager script bind on your Canvas. 13 | 14 | 2.每个界面的根物体上挂继承Fragment的实现脚本 15 | 16 | The root object's script in every page should implement Fragment script. 17 | 18 | 19 | 20 | ## Fragment 21 | **Fragment中包含生命周期的回调:** 22 | 23 | **OnEnterStack:** 24 | 25 | fragment进栈时回调, 可以用于实现与OnEnable不同的逻辑 26 | 27 | The method will callback when a fragment enter the stack, this use for implement logic that different with OnEnable method. 28 | 29 | **OnExitStack:** 30 | 31 | fragment出栈时回调, 可以用于实现与OnDisable不同的逻辑 32 | 33 | The method will callback when a fragment exit the stack, this use for implement logic that different with OnDisable method. 34 | 35 | **OnIntent:** 36 | 37 | 通过FragmentIntent启动fragment时回调, 可用于界面跳转时传些数据 38 | 39 | The method will callback when start a fragment by FragmentIntent, this use for pass data when pages switch. 40 | 41 | **DoExitAnimation:** 42 | 43 | 可以在这里实现界面退出动画 44 | 45 | You can override this method to implement animation when a fragment exit. 46 | 47 | **DoEnterAnimation:** 48 | 49 | 可以在这里实现界面进入动画 50 | 51 | You can override this method to implement animation when a fragment enter. 52 | 53 | **OnDynamicInstantiated:** 54 | 55 | fragment动态加载时回调 56 | 57 | The method will callback when dynamic loading a fragment. 58 | 59 | 60 | **Fragment中包含按键时的回调** 61 | 62 | **OnBackPressed:** 63 | 64 | 按返回键时回调 65 | 66 | The method will callback when Back key pressed. 67 | 68 | **OnMenuPressed:** 69 | 70 | 按菜单键时回调 71 | 72 | The method will callback when Menu key pressed. 73 | 74 | **OnHomePressed:** 75 | 76 | 按Home键时回调 77 | 78 | The method will callback when Home key pressed. 79 | 80 | **OnLongBackPressed:** 81 | 82 | 长按返回键时回调 83 | 84 | The method will callback when Back key long pressed. 85 | 86 | 87 | ## FragmentManager 88 | 89 | **支持两种形式的Fragment** 90 | 91 | **静态Fragment:** 92 | 93 | 在Scene中已经存在的物体上继承Fragment的实现脚本,第一个可见物体上的Fragment被认为是默认显示的界面。 94 | 95 | Static Fragment: A script implement Fragment script on a exist object in a scene, and the default page which the first visible fragment will show. 96 | 97 | 98 | **动态Fragment:** 99 | 100 | 在编辑器中的FragmentManager脚本上配置界面的任意个Prefab,每个Prefab认为是一个界面,初始化时需要手动显示默认显示的界面。需要在TagManager中添加名为“UnInstantiateFragment”的tag 101 | 102 | Dynamic Fragment: The FragmentManager in the editor should setup page's any Prefab, every Prefab is know as a page, 103 | The default display page needs to be manually displayed during initialization. 104 | A tag called "UnInstantiateFragment" needs to be added to the TagManager. 105 | 106 | 107 | 108 | **支持多种Fragment启动模式** 109 | 110 | 效果与安卓中activity启动模式一样 111 | 112 | The effect is the same as in android's activity startup mode 113 | 114 | **FLAG_NEW_INSTANCE:** 115 | 116 | 以一个新的Fragment实例启动 117 | 118 | Start with a new Fragment instance 119 | 120 | **FLAG_CLEAR_TOP:** 121 | 122 | 若栈中存在该Fragment实例, 则将栈顶的其他Fragment实例都清空, 并将该Fragment实例置顶并显示 123 | 124 | If the Fragment instance exists on the stack, then all the other Fragment instances on the top of the stack are cleared and the Fragment instance is placed on the top and displayed. 125 | 126 | **FLAG_SINGLE_INSTANCE:** 127 | 128 | 若栈中存在该Fragment实例, 则将该Fragment实例置顶并显示 129 | 130 | If the Fragment instance exists on the stack, the Fragment instance is placed on top and displayed. 131 | 132 | 133 | ## License 134 | 135 | MIT License 136 | 137 | Copyright (c) 2017 Hcq 138 | 139 | Permission is hereby granted, free of charge, to any person obtaining a copy 140 | of this software and associated documentation files (the "Software"), to deal 141 | in the Software without restriction, including without limitation the rights 142 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 143 | copies of the Software, and to permit persons to whom the Software is 144 | furnished to do so, subject to the following conditions: 145 | 146 | The above copyright notice and this permission notice shall be included in all 147 | copies or substantial portions of the Software. 148 | 149 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 150 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 151 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 152 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 153 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 154 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 155 | SOFTWARE. 156 | --------------------------------------------------------------------------------