Compare commits
926 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ab6007892 | |||
| b6e8928b1a | |||
| 3a3d53424c | |||
| 71f419a3cd | |||
| 0e27410460 | |||
| 29185a47bd | |||
| 6821b26706 | |||
| 5bdbe0f0ea | |||
| afe2a9bced | |||
| c0d88af234 | |||
| 3b4c1bd51c | |||
| 3c9f556533 | |||
| 7f1a74825d | |||
| 22d46c5260 | |||
| 466aaf21dd | |||
| 56e71ac580 | |||
| f45b6aaa3f | |||
| e473c3c440 | |||
| 8f2be39bf4 | |||
| 92c10830ff | |||
| dcb89f58c3 | |||
| d39c4b54d1 | |||
| 504182ceae | |||
| bc1cfe444b | |||
| 0e0f773df7 | |||
| be2be99537 | |||
| afcf1ced36 | |||
| 5b33d3d5ff | |||
| dbef6a691a | |||
| dd238884bf | |||
| 046ed3df5b | |||
| 4996ce1a84 | |||
| b8f7ff825d | |||
| 6fb9a9b3a2 | |||
| 34ebb3bf19 | |||
| dbf665526d | |||
| 6c7f529eff | |||
| c414d3a2a6 | |||
| 8eba647d75 | |||
| c3568067b7 | |||
| 72580f089d | |||
| c508ec892d | |||
| ff2d4a48f1 | |||
| 62364eb6d5 | |||
| ce5469a69d | |||
| 93c31fd71d | |||
| 461f637818 | |||
| 6b3b18b8ed | |||
| b5ca468397 | |||
| 80956bfac6 | |||
| 5d382c440f | |||
| d28c939a4c | |||
| 8bd02145cf | |||
| debeca1fb2 | |||
| 9da54f9fc1 | |||
| a13d053867 | |||
| eda7201fe8 | |||
| b1edef49a4 | |||
| a2db94a8c4 | |||
| 57495cff84 | |||
| eff5cde844 | |||
| c365eadf1e | |||
| 5d02681b05 | |||
| 6e17ff734a | |||
| 02ed923e7b | |||
| 421335d98c | |||
| 2618f49556 | |||
| 328116600f | |||
| a10b1426cd | |||
| 5468856a93 | |||
| 8f3a7de321 | |||
| 2de1fb9ac8 | |||
| 27a2d81a71 | |||
| 85ed3a6ce3 | |||
| b34f1093de | |||
| de1dbe70de | |||
| c593c646ca | |||
| 0cb5307a61 | |||
| 8ab3b7986c | |||
| bbdf3e7c6f | |||
| bdb756b665 | |||
| 6611ec83a2 | |||
| a917d6a626 | |||
| 7511ce577d | |||
| e7d0a72440 | |||
| 44923ef66e | |||
| 2760bc7298 | |||
| d428e96b03 | |||
| 67495961e5 | |||
| 7b88703e43 | |||
| c40e66ef3d | |||
| 53fb131d0e | |||
| 37969f6cb3 | |||
| a0ba3af012 | |||
| 6082dba6a7 | |||
| 43327e8123 | |||
| 0a5bc19d0f | |||
| dd52e1eaee | |||
| 22aa055843 | |||
| 448fc5cbb4 | |||
| b4fe3b408c | |||
| 6ecc7924ba | |||
| 0b82902233 | |||
| 597dbd4145 | |||
| 1ee949ff1b | |||
| 2a29cb5b3e | |||
| 208ab665da | |||
| 3e20314cfa | |||
| 5b8e9a54d9 | |||
| d3c30b35d9 | |||
| 8bb3795931 | |||
| 9383cd001d | |||
| 6d5f770066 | |||
| ce2cafed5b | |||
| 68352218ac | |||
| e3736e4214 | |||
| d6bbf92339 | |||
| 0e833aee3c | |||
| 5949bc88ea | |||
| 30bd261a10 | |||
| f92279484f | |||
| 2205d1186d | |||
| cd0948a9a4 | |||
| 6589aff4ac | |||
| d34c16b1a5 | |||
| 05813253f9 | |||
| 4ab7d26030 | |||
| 162545d7e9 | |||
| 4904ea19cb | |||
| b941f91556 | |||
| f917316135 | |||
| 6235a19588 | |||
| c47fc3d1d5 | |||
| e6d285c6df | |||
| a26a6beab2 | |||
| b00a05b9ed | |||
| bfbb7ad004 | |||
| 4dd52b1790 | |||
| aef914e0fd | |||
| 2ef35f58a3 | |||
| 8aaf8b7b25 | |||
| c330b59a9f | |||
| 639e4221e8 | |||
| 1ff3c28de8 | |||
| 89092676e3 | |||
| bacc871dd2 | |||
| 0bc9812c23 | |||
| a4d98971b3 | |||
| 1b0ec64489 | |||
| 345e894007 | |||
| 1fb1708df9 | |||
| b9edbf766e | |||
| fe30e60235 | |||
| 6e7c31110f | |||
| e39f634d34 | |||
| 5851fd77c4 | |||
| 0fbbbc8d99 | |||
| 69078366de | |||
| 084b589a10 | |||
| 07ae324586 | |||
| 819c87c530 | |||
| 3bb9c4fd0f | |||
| 910a304849 | |||
| 2ecdbbae52 | |||
| fe2e3173b8 | |||
| 21c6e3c715 | |||
| 29beea0ff9 | |||
| 1e16d9c1fb | |||
| 31d7a2a301 | |||
| 5f1d49b0bd | |||
| ee66f218ca | |||
| 3a0831a334 | |||
| add2f9ba4f | |||
| ca6a8d5c16 | |||
| 84eba1aefa | |||
| 289ea4c971 | |||
| 821b03376c | |||
| 19fe1cffef | |||
| b8fcb50874 | |||
| 9c45c31190 | |||
| 895790f697 | |||
| 43c7e8c2a0 | |||
| 904a66115c | |||
| d0932e8e37 | |||
| 22009013eb | |||
| da4668aa2b | |||
| 00ce232420 | |||
| 5b176b5cef | |||
| 15709f62f8 | |||
| 9168236534 | |||
| 16e709e8ab | |||
| 94c39f0f34 | |||
| 16fea625be | |||
| 6c69694cfe | |||
| 561d783479 | |||
| 1bd2e60200 | |||
| ec0e1b2dad | |||
| 9958fc5017 | |||
| 11dfc0d2f3 | |||
| 34246d1f37 | |||
| 3d6c0220e0 | |||
| ecbd318186 | |||
| 34809bd8ea | |||
| aa5fbe9e94 | |||
| 9fbb7df15a | |||
| d55f9a0abf | |||
| a932f3b782 | |||
| 9ea95d69a1 | |||
| e783b92905 | |||
| d380fdeb13 | |||
| 987bf79121 | |||
| be0ebd0fae | |||
| a6538b7a2a | |||
| 40194d91c0 | |||
| c8b2b33de0 | |||
| 7114f545ff | |||
| b4423bcaa2 | |||
| b34fd41650 | |||
| 199a77182b | |||
| 0a0f00172d | |||
| 25ca9487fb | |||
| 231ee4c9af | |||
| c872218446 | |||
| 8e8c6527d4 | |||
| 3b4e237eba | |||
| 9b1cb68f0a | |||
| 4ba8acaf08 | |||
| 02d8d4516c | |||
| 94829d2749 | |||
| 1522a0990f | |||
| 0a613a7339 | |||
| b4a518fe3e | |||
| 538e046368 | |||
| bb44d14370 | |||
| 230ec689d4 | |||
| c7605a94b9 | |||
| 864104de3e | |||
| a8e1cfa2bc | |||
| 207dd27113 | |||
| 802b6f9b6b | |||
| 0ff9d5dd9b | |||
| 6e509481bb | |||
| 054a21f3f8 | |||
| 2e3bbaeec2 | |||
| 18e739fc7b | |||
| ca7596e1ca | |||
| 38103da2eb | |||
| 0c2275def1 | |||
| a0da1b99c0 | |||
| 427814839a | |||
| 007f9af3eb | |||
| da4e1d26d3 | |||
| 2ce1375ce7 | |||
| 016bf3e185 | |||
| 214942f918 | |||
| af53ac1964 | |||
| 991166534f | |||
| 39feab437d | |||
| ba8d37e8e0 | |||
| 885493f2e5 | |||
| 65fd04975d | |||
| 1a45f43232 | |||
| 28c384aa0d | |||
| 99c922bf3a | |||
| 009033be79 | |||
| 5d2e6dd417 | |||
| 9c71a47d9b | |||
| db0d73b428 | |||
| 968cb47163 | |||
| 6f28edc92c | |||
| 2b94139435 | |||
| cb21b4075d | |||
| d23e17c20b | |||
| 92f2a089ee | |||
| 983f9e2835 | |||
| 14fad8b745 | |||
| 098bd14a03 | |||
| cfa4047adf | |||
| bbf437735f | |||
| 5540c94e6c | |||
| 78981651c4 | |||
| 5df377e43d | |||
| 02af74894a | |||
| 8533ecfcdf | |||
| 6d37df16b2 | |||
| d4542a4948 | |||
| 0d99c14847 | |||
| fc1aed9605 | |||
| ebf0bcc07f | |||
| fb0221226f | |||
| 6277bfc89f | |||
| 4181918fc5 | |||
| cd06dfdb28 | |||
| 9509e3c32b | |||
| b574cf97a0 | |||
| c2fc35fc41 | |||
| 1bbb4dcc23 | |||
| f9a5386dc7 | |||
| c962395581 | |||
| 015454238a | |||
| a5341f37c6 | |||
| c519404752 | |||
| 4c9ebbbd61 | |||
| 0d958b2d04 | |||
| ab7b16e789 | |||
| c482da8ceb | |||
| b348684ed5 | |||
| 6d63ccd754 | |||
| 579bcbd9dd | |||
| bcba7c8844 | |||
| 0adb374146 | |||
| 74d7cdfb42 | |||
| 3de61d5ee2 | |||
| ba1b6170eb | |||
| 1f4daa04c2 | |||
| 5cebed07d8 | |||
| 9b33687c10 | |||
| da4162b307 | |||
| 92ca4909ce | |||
| 65d03846a1 | |||
| fe86659db7 | |||
| 153bd32cfe | |||
| 99fd41c58b | |||
| d217c3ad2b | |||
| 0f678d20fe | |||
| 102c9b3019 | |||
| fd4e6fea61 | |||
| 54570ac7c6 | |||
| 38359e25ad | |||
| 2cf63838ae | |||
| 49e8545aec | |||
| b34ea2444d | |||
| 984d4c41d8 | |||
| 8d372452b4 | |||
| 2fc16bb1f4 | |||
| 8903e4e610 | |||
| 5634de2eee | |||
| 1957ae3919 | |||
| a4f8c0528c | |||
| e4548b26bd | |||
| d540b1ddde | |||
| aaeb752911 | |||
| 966caad519 | |||
| a62c3a23dc | |||
| 7bbc3d5910 | |||
| e2afb1e22f | |||
| 8cca1178fd | |||
| a09a0e9e32 | |||
| 43c76faa20 | |||
| 5787a350ab | |||
| 9abb80de64 | |||
| 7d90458d99 | |||
| 5d5f14acd8 | |||
| bed519f0c0 | |||
| 7c47e2e20e | |||
| f909cd4101 | |||
| 8c24aa3fc9 | |||
| 7531d80f1c | |||
| c4c1906cae | |||
| 4f717c5840 | |||
| fbd83ef500 | |||
| 2a91145366 | |||
| f5d72aa0a5 | |||
| 65f67c98f4 | |||
| 1f79c2573f | |||
| bc840dde46 | |||
| 57ed039857 | |||
| 11f0e8c84e | |||
| dd19c866d4 | |||
| 801fed9843 | |||
| 847b5c0917 | |||
| c64056ca7b | |||
| 269c3e29b5 | |||
| 002bbb4a4a | |||
| 14011a5bc2 | |||
| 23f2242c9a | |||
| 4fd92a4002 | |||
| 9c57089b0e | |||
| 3b11cdc72a | |||
| 4edaad2cf4 | |||
| 92fc0621e2 | |||
| e9f4392c48 | |||
| 4df40becaf | |||
| ba11e7c7d7 | |||
| ae671f22c6 | |||
| f22f58212b | |||
| 54ff1c360d | |||
| 772d6c3ef3 | |||
| a94c3b3c26 | |||
| d0ffc4ceb1 | |||
| 597ce487aa | |||
| 87eb8d94fd | |||
| 4944fc516a | |||
| 7537384339 | |||
| 8fd134512f | |||
| f566fc6475 | |||
| 9cbcb48a9b | |||
| 817956cef3 | |||
| 3c1aa7aa42 | |||
| 7598e8f160 | |||
| ba011e7242 | |||
| ecdf20db8f | |||
| 3a7f39321c | |||
| e75d83e7a4 | |||
| 0461c49d23 | |||
| c4f7fa5332 | |||
| 3a9f304735 | |||
| 1d5cb1744f | |||
| b61b0b5451 | |||
| e3a4631e44 | |||
| d7f798e9a0 | |||
| ae2c83e32b | |||
| 059b2ed4f0 | |||
| 338658cd9f | |||
| 2cdb4a6bc2 | |||
| 1a4d5a7954 | |||
| 22ef3e7cd9 | |||
| 5325e707e6 | |||
| 1dc0a6b76a | |||
| 2689d68bab | |||
| f8b8176988 | |||
| 0c5bf2bfe9 | |||
| 218a12962f | |||
| 916d2ec76a | |||
| 1b1ba5deef | |||
| 58b2df4996 | |||
| 8b45517915 | |||
| 3cca07fefd | |||
| 276ae23f13 | |||
| c1b2ffeb78 | |||
| 3b812be84e | |||
| 262ee34201 | |||
| 5d86bd5d02 | |||
| 3b6271c4f4 | |||
| 1671a3d50f | |||
| 0ab318e804 | |||
| 53719bd94a | |||
| 935b7d9e10 | |||
| e3bf19b972 | |||
| c36f09d3e9 | |||
| 9936a89118 | |||
| 562424cd8f | |||
| 0c3fb83d0a | |||
| 7df352a44b | |||
| 1443d377ad | |||
| e0bca25411 | |||
| e94d47b1a5 | |||
| 9d3a1674c4 | |||
| 24d81a4153 | |||
| 5723a8017b | |||
| 72055cd998 | |||
| 9cd8b4d960 | |||
| f39b368c1e | |||
| a4543351fe | |||
| 88ac013166 | |||
| 5d336b9090 | |||
| 45b3209b9b | |||
| da16cf6ada | |||
| 774a841fb5 | |||
| 020ffdaa84 | |||
| 2ef096b3a0 | |||
| 69bde3e80d | |||
| e6aa7db35a | |||
| 0124d98111 | |||
| c00a3836a5 | |||
| 66f9118e78 | |||
| f261b90a73 | |||
| a1602e0221 | |||
| b4e9ce8478 | |||
| 35d7cbb1d3 | |||
| 6ab678bb18 | |||
| 14ec9cf0a1 | |||
| a225bf2cf1 | |||
| 9b904cd895 | |||
| 11a16092a7 | |||
| b9b7f940b9 | |||
| e542728ff6 | |||
| 1eeb6e2d73 | |||
| cf9d53aca2 | |||
| 83463c792c | |||
| d5c7571a97 | |||
| 75c27bc232 | |||
| cbcc35268d | |||
| 11ba247ac4 | |||
| f411e81949 | |||
| 45d7cb7218 | |||
| 81f42d3951 | |||
| 2f7aed3e34 | |||
| 01f8261f0b | |||
| 489d7696cc | |||
| 0661f08a07 | |||
| 206475e6ab | |||
| a4a68e5b39 | |||
| de7ab0e0cb | |||
| 5f7b5ce81c | |||
| 36d7ea5100 | |||
| 33f8cf3802 | |||
| f6da876fdf | |||
| 96c5dc7b74 | |||
| a37931b62d | |||
| 5c848d9bf5 | |||
| 265b805fa9 | |||
| c4dfe33a5e | |||
| 999eeb47ba | |||
| a5bf02cfec | |||
| c10186e50a | |||
| 7a1cbf99d4 | |||
| c9c4000536 | |||
| 656bbc1b1c | |||
| 3815a08af5 | |||
| 404fdb6496 | |||
| 573f355c15 | |||
| bd0c891795 | |||
| f4857a3da9 | |||
| e074c3caf1 | |||
| 0f4c7503b1 | |||
| 2cb142a31f | |||
| 2b05ea8d92 | |||
| d255e1ea4a | |||
| 23846dbf23 | |||
| 6fcb817fb8 | |||
| e2ebfd01df | |||
| cf70929204 | |||
| 624e3f7553 | |||
| 3cc8538db3 | |||
| a9a65436bb | |||
| 353dabfc47 | |||
| 1bdf0f5b78 | |||
| 6696d7f71d | |||
| 59a6c7e576 | |||
| 0b0148635e | |||
| c354d8ea92 | |||
| 9562cdaccb | |||
| bcfff8a33a | |||
| f5c409ba90 | |||
| 2f23520330 | |||
| a95694cbfc | |||
| 6cfba6495f | |||
| b9f3de1c64 | |||
| c67b56e7af | |||
| bf39f07691 | |||
| a9e46f0de6 | |||
| 05478fa8fa | |||
| d123afc3f7 | |||
| b1b3c15300 | |||
| 49bae50739 | |||
| 9b5459af8e | |||
| 96d2ea57f5 | |||
| b78c5f4ece | |||
| 341522ccaa | |||
| 833628e42f | |||
| 50c1c6fdc9 | |||
| 213386e822 | |||
| 17317ed274 | |||
| 652ae8c967 | |||
| ec0e8cbdaf | |||
| c15d4c9035 | |||
| 39dfdd0ef0 | |||
| d25bc58249 | |||
| 194a197e83 | |||
| bd02f34bcf | |||
| 7d5f03bb6e | |||
| 60f41e168f | |||
| 680b16aa25 | |||
| 2394c03dca | |||
| c8f211f2bf | |||
| 9076ba8933 | |||
| 08e79bfc5c | |||
| e4808516aa | |||
| 5888104e98 | |||
| 2b8d29759a | |||
| 8e4b56ff17 | |||
| 23c5761c14 | |||
| 835ec0c3a0 | |||
| d2dce0b6f8 | |||
| 3f8628af01 | |||
| 40c6fae07c | |||
| e1185fda93 | |||
| 458ed903c5 | |||
| 4b640f4f01 | |||
| 8743c5efd0 | |||
| 9bd9d31d40 | |||
| 7e3d720720 | |||
| 7a512191ab | |||
| af767863bb | |||
| 1b233f4f87 | |||
| 3a840df79e | |||
| 6851e3b072 | |||
| 5a2b079872 | |||
| f683f987d8 | |||
| 3626621e87 | |||
| cc2d1eb002 | |||
| 5ba19bcf8b | |||
| 8391686e28 | |||
| 38327c917f | |||
| fca0f399b2 | |||
| e3b7ac0e99 | |||
| 04cd357f68 | |||
| 68f48f714d | |||
| fa586c494f | |||
| b886a0da64 | |||
| 0616aec3d2 | |||
| 5df36a6601 | |||
| 7d6f295e72 | |||
| 1c952b6dcb | |||
| 7e7c2a0fd7 | |||
| a15444d237 | |||
| 5b100f3b22 | |||
| 9fa8a48c56 | |||
| cb54a2a7e1 | |||
| ed02713ccc | |||
| 68e3fd2093 | |||
| a43f73d7b1 | |||
| 61e0c4ed0a | |||
| 53e0629b1d | |||
| 2b1d6a3d8a | |||
| 5ba1fb3d95 | |||
| 1b7c15cdb5 | |||
| 81fd85e993 | |||
| 8f4c08d5b3 | |||
| 61b6429851 | |||
| bbc6b39c08 | |||
| 3f812f4d6d | |||
| c9b15e4239 | |||
| 5fbdb3d481 | |||
| c59e1cd7fc | |||
| ce891e47da | |||
| 7160e4a42e | |||
| eba857a285 | |||
| a1dd02c780 | |||
| 87ff5d629b | |||
| 6b75523428 | |||
| 773434d4f6 | |||
| ad6dcd0314 | |||
| b9e29ad87d | |||
| 32b965ba87 | |||
| f1b315c9ea | |||
| 459fc75af3 | |||
| 9b0cd3511f | |||
| af9b988507 | |||
| 36f297c35b | |||
| ff959f71a7 | |||
| 0a4312ada6 | |||
| 5411cdc07a | |||
| a8c6fba3c1 | |||
| 11b115b47b | |||
| 22edf5ce46 | |||
| f43f7df7f3 | |||
| 3a2633d818 | |||
| 04a62bcf74 | |||
| 6c1320168c | |||
| 8657c91002 | |||
| bafe492009 | |||
| c6197ef6a3 | |||
| 1b3f16bcd5 | |||
| 28712fdeca | |||
| 0c30b68a9e | |||
| 30c4bee432 | |||
| ece9ced085 | |||
| f231105752 | |||
| 91dfc1e086 | |||
| b2c59c17aa | |||
| 10d1a920f0 | |||
| 4cb79a14fc | |||
| 402b9bd8dc | |||
| c39cc9d93b | |||
| aad56ab0a7 | |||
| fe18e493a9 | |||
| 5d14166508 | |||
| e1a745e3b5 | |||
| a0cac28ed0 | |||
| c205dc8672 | |||
| 5c0ed4cf7d | |||
| 780472a17f | |||
| 0264db3d54 | |||
| c117594669 | |||
| 5214bd8936 | |||
| a1195be08e | |||
| b69d366538 | |||
| c9de6f0dc3 | |||
| 21be693a9a | |||
| 129362fcd0 | |||
| 75e2fcc3ce | |||
| 4f56b57b0e | |||
| f9bbdf3427 | |||
| fcf200e169 | |||
| 7d668c8525 | |||
| ebd4a32bfc | |||
| 6aa739231d | |||
| 8877d32ced | |||
| 7f025ae845 | |||
| 1b2dae2135 | |||
| 6e4e9df616 | |||
| 49e868a505 | |||
| f1b70e0367 | |||
| 1d0e747578 | |||
| 2c72d07cab | |||
| 31c057f9f8 | |||
| d3033df9da | |||
| 459d82b1c6 | |||
| 85d7ca640e | |||
| c1b7f2f092 | |||
| b7a7e0d4ad | |||
| dc7f6d58f9 | |||
| a2a10bd0d3 | |||
| b54c8ee6ee | |||
| 08d275690a | |||
| 1c307f751e | |||
| 6f06a0f7fc | |||
| a095ace30e | |||
| a486f61f5f | |||
| 14e0abc240 | |||
| 32203c48bd | |||
| 9d6024f603 | |||
| a4dd4e48e7 | |||
| e6f7456a0f | |||
| fca79c9b0c | |||
| 4ad7f11e93 | |||
| 0412bdc996 | |||
| 31faeaada3 | |||
| 72539ca973 | |||
| ef94630aa1 | |||
| cb696f9992 | |||
| aa23e404e1 | |||
| 4c0749640f | |||
| ee5661f304 | |||
| ddefdc4f34 | |||
| f2a0af1646 | |||
| 7ded61c2bc | |||
| 08aabcf6dd | |||
| e19af7e67d | |||
| 62aa07e28e | |||
| 03b0bf747e | |||
| 8dc75aed55 | |||
| d5f5e99010 | |||
| 18c46d191e | |||
| e9f92430b2 | |||
| 3106865449 | |||
| 375e7a59e2 | |||
| bc4a2def42 | |||
| 8204a6cf27 | |||
| 797292dbe5 | |||
| 6e7a33b3a1 | |||
| 2bfea00c72 | |||
| 81441a724b | |||
| 82c8d8dd9a | |||
| 8751a9fe53 | |||
| 9cf561fcf1 | |||
| 332559c67d | |||
| 56557f0092 | |||
| 1e6cb7b1ad | |||
| 7f419b7e78 | |||
| 973a90e071 | |||
| 66a8ca36e4 | |||
| 3715007156 | |||
| 5158685c02 | |||
| 61d3371ea5 | |||
| 0491507e67 | |||
| fcd4ad874a | |||
| e2668fcdf2 | |||
| f3ac2b2cec | |||
| 8b84391e36 | |||
| 1b3ca347f5 | |||
| 2dced7bfbf | |||
| 8ba4ce36a1 | |||
| cf60b09225 | |||
| 427ec45d42 | |||
| ac9f8fe89c | |||
| 6817990555 | |||
| d395cde316 | |||
| 20272eccb8 | |||
| 091ae8abff | |||
| 6e87690649 | |||
| d5a1bd3859 | |||
| a1e4643a25 | |||
| 71c0450614 | |||
| d469caad69 | |||
| 5cc3d4fbfb | |||
| a8691ee3a5 | |||
| 91d7941921 | |||
| 0bc7a0953e | |||
| c60bea5952 | |||
| 4db648ad25 | |||
| 0bb8342873 | |||
| d4f2a88fdf | |||
| af45d39841 | |||
| 66f5b0b210 | |||
| 4a3b79f1b4 | |||
| 12a100def8 | |||
| 47971f607a | |||
| 03a4d342a3 | |||
| 4f5abfefec | |||
| e1ee3c06e8 | |||
| 17ba704472 | |||
| e5391fa1f4 | |||
| c0647017b5 | |||
| 3686bb4b44 | |||
| 76c8ca4b20 | |||
| c53e64027b | |||
| c15d236320 | |||
| 281504c9c6 | |||
| eaf0ebe62b | |||
| a4a08662be | |||
| e8a0ffeca5 | |||
| 1399cc6fbd | |||
| 8b44ad4b08 | |||
| e4a1a6e293 | |||
| ba00786b91 | |||
| 5e7529d1e6 | |||
| e75108113a | |||
| 6d51b0d420 | |||
| c3b199755e | |||
| d57d8e9da5 | |||
| d24e1c5355 | |||
| 95c94560be | |||
| 7b4ed52eb1 | |||
| cab8c15474 | |||
| 72f5d59a75 | |||
| 273adc8d1b | |||
| 5f0f28cb0e | |||
| e1c9fe120b | |||
| 630580beb6 | |||
| 68a2c43580 | |||
| 817fce6d10 | |||
| 6e85afaee6 | |||
| 98c5096f67 | |||
| 57c7ced59d | |||
| 73e6d38344 | |||
| bd128bf8b0 | |||
| 16e8808ce5 | |||
| f4088fcb6b | |||
| 63b8aa24e8 | |||
| 5744491606 | |||
| f5ecbef724 | |||
| f176a2c70e | |||
| 51c124d3e4 | |||
| 5f6c97336e | |||
| 894eb77d5d | |||
| d1b5a1f517 | |||
| 300d5f8d91 | |||
| bbc885f783 | |||
| 6badeeebe5 | |||
| e282806422 | |||
| 629807584b | |||
| 922c0e53d2 | |||
| ec9fcd473a | |||
| de9f415ded | |||
| fd5ca2c2fc | |||
| c0b9ddc4a3 | |||
| 43f33083f1 | |||
| 2b483e6adb | |||
| 0cf0f42ca4 | |||
| c9ccea3f84 | |||
| c2dee28132 | |||
| 4fd4709182 | |||
| 00ccc0eb6a | |||
| ed91f51482 | |||
| c2cea95aa5 | |||
| 274027cb64 | |||
| b4a26344d9 | |||
| 580c708788 | |||
| f4d6380094 | |||
| e44dc06a61 | |||
| b6184f5b41 | |||
| e6fc2f397e | |||
| 60d0b62675 | |||
| 7a8eb1833f | |||
| 6367b76b9d | |||
| 977b685071 | |||
| b97d418158 | |||
| 0e4cb372d5 | |||
| 2ec7576ae9 | |||
| c4bf4c3067 | |||
| ea9bbcad27 | |||
| 71be1f2ed5 | |||
| 349bb91c6c | |||
| 52da673358 | |||
| ce0b9d1413 | |||
| 8ef332f3e5 | |||
| a4002f83c1 | |||
| 64d756d8a9 | |||
| 187fe47268 | |||
| 060f3a0b1b | |||
| 4dcc5bc564 | |||
| 52efac6643 | |||
| 97c91fb7aa | |||
| efcc598550 | |||
| fd5fc1f485 | |||
| f713d4057f | |||
| 4ebbea8e86 | |||
| 5515e6f788 | |||
| 65a6315f1b | |||
| aafe32bb3d | |||
| 1c6c783dbe | |||
| 1e322f47d4 | |||
| 37196abe77 | |||
| e476cf5ce4 | |||
| dc4b1e7a90 | |||
| 95d188d5f1 | |||
| 4dd60ca855 | |||
| 5067917295 | |||
| e620ef27ee | |||
| 868dc17425 | |||
| 03966f356f | |||
| c28ab32874 | |||
| 32b7ab64d5 | |||
| 79d8e1851a | |||
| e3c1743b57 | |||
| ed257bf5b7 | |||
| f918b8709e | |||
| ad46f5bd55 | |||
| 4e2f9bc349 | |||
| a3e8d1587b | |||
| ce556e213c | |||
| 7c3581d8be | |||
| 8c53fd4869 | |||
| 540862e95a | |||
| e08ce7fe18 | |||
| be2a455088 | |||
| 6333dfacb1 | |||
| 56aa1c405c | |||
| 55b76a5fca | |||
| c9453655d5 | |||
| f241227e7a | |||
| f304bf0362 | |||
| 7d1c12d3a6 |
@@ -0,0 +1,14 @@
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
test-ios14_5-iPhone_12_Pro:
|
||||
macos:
|
||||
xcode: 13.4.1
|
||||
steps:
|
||||
- checkout
|
||||
- run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=14.5,name=iPhone 12 Pro'
|
||||
|
||||
workflows:
|
||||
test:
|
||||
jobs:
|
||||
- test-ios14_5-iPhone_12_Pro
|
||||
@@ -0,0 +1 @@
|
||||
github: SCENEE
|
||||
@@ -0,0 +1,40 @@
|
||||
> Please fill out this template appropriately when filing a bug report.
|
||||
>
|
||||
> Please remove this line and everything above it before submitting.
|
||||
|
||||
### Description
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
**Code example that reproduces the issue**
|
||||
|
||||
|
||||
**How do you display panel(s)?**
|
||||
|
||||
* Add as child view controllers
|
||||
* Present modally
|
||||
|
||||
**How many panels do you displays?**
|
||||
|
||||
* 1
|
||||
* 2+
|
||||
|
||||
### Environment
|
||||
|
||||
**Library version**
|
||||
|
||||
**Installation method**
|
||||
|
||||
* CocoaPods
|
||||
* Carthage
|
||||
* Swift Package Manager
|
||||
|
||||
**iOS version(s)**
|
||||
|
||||
|
||||
**Xcode version**
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- swift: "5.10"
|
||||
xcode: "15.4"
|
||||
runs-on: macos-14
|
||||
- swift: "5.9"
|
||||
xcode: "15.2"
|
||||
runs-on: macos-13
|
||||
- swift: "5.8"
|
||||
xcode: "14.3.1"
|
||||
runs-on: macos-13
|
||||
- swift: "5.7"
|
||||
xcode: "14.1"
|
||||
runs-on: macos-12
|
||||
- swift: "5.6"
|
||||
xcode: "13.4.1"
|
||||
runs-on: macos-12
|
||||
- swift: "5.5"
|
||||
xcode: "13.2.1"
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Building in Swift ${{ matrix.swift }}
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=${{ matrix.swift }} clean build
|
||||
|
||||
test:
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: "17.5"
|
||||
xcode: "15.4"
|
||||
sim: "iPhone 15 Pro"
|
||||
parallel: NO # Stop random test job failures
|
||||
runs-on: macos-14
|
||||
- os: "16.4"
|
||||
xcode: "14.3.1"
|
||||
sim: "iPhone 14 Pro"
|
||||
parallel: NO # Stop random test job failures
|
||||
runs-on: macos-13
|
||||
- os: "15.5"
|
||||
xcode: "13.4.1"
|
||||
sim: "iPhone 13 Pro"
|
||||
parallel: NO # Stop random test job failures
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Testing in iOS ${{ matrix.os }}
|
||||
run: |
|
||||
xcodebuild clean test \
|
||||
-workspace FloatingPanel.xcworkspace \
|
||||
-scheme FloatingPanel \
|
||||
-destination 'platform=iOS Simulator,OS=${{ matrix.os }},name=${{ matrix.sim }}' \
|
||||
-parallel-testing-enabled '${{ matrix.parallel }}'
|
||||
timeout-minutes: 20
|
||||
|
||||
example:
|
||||
runs-on: macos-14
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- example: "Maps"
|
||||
- example: "Maps-SwiftUI"
|
||||
- example: "Stocks"
|
||||
- example: "Samples"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Building ${{ matrix.example }}
|
||||
run: |
|
||||
xcodebuild clean build \
|
||||
-workspace FloatingPanel.xcworkspace \
|
||||
-scheme ${{ matrix.example }} \
|
||||
-sdk iphonesimulator
|
||||
|
||||
swiftpm:
|
||||
runs-on: macos-14
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [iphoneos, iphonesimulator]
|
||||
arch: [x86_64, arm64]
|
||||
exclude:
|
||||
- platform: iphoneos
|
||||
arch: x86_64
|
||||
include:
|
||||
# 17.2
|
||||
- platform: iphoneos
|
||||
sys: "ios17.2"
|
||||
- platform: iphonesimulator
|
||||
sys: "ios17.2-simulator"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: "Swift Package Manager build"
|
||||
run: |
|
||||
xcrun swift build \
|
||||
--sdk "$(xcrun --sdk ${{ matrix.platform }} --show-sdk-path)" \
|
||||
-Xswiftc "-target" -Xswiftc "${{ matrix.arch }}-apple-${{ matrix.sys }}"
|
||||
|
||||
swiftpm_old:
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# 16.4
|
||||
- target: "x86_64-apple-ios16.4-simulator"
|
||||
xcode: "14.3.1"
|
||||
runs-on: macos-13
|
||||
- target: "arm64-apple-ios16.4-simulator"
|
||||
xcode: "14.3.1"
|
||||
runs-on: macos-13
|
||||
# 15.7
|
||||
- target: "x86_64-apple-ios15.7-simulator"
|
||||
xcode: "14.1"
|
||||
runs-on: macos-12
|
||||
- target: "arm64-apple-ios15.7-simulator"
|
||||
xcode: "14.1"
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: "Swift Package Manager build"
|
||||
run: |
|
||||
swift build \
|
||||
-Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" \
|
||||
-Xswiftc "-target" -Xswiftc "${{ matrix.target }}"
|
||||
|
||||
cocoapods:
|
||||
runs-on: macos-14
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: "CocoaPods: pod lib lint"
|
||||
run: pod lib lint --allow-warnings
|
||||
- name: "CocoaPods: pod spec lint"
|
||||
run: pod spec lint --allow-warnings
|
||||
@@ -17,11 +17,13 @@ DerivedData/
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
IDEWorkspaceChecks.plis
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
*.xcsettings
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
@@ -29,6 +31,9 @@ xcuserdata/
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Swift Package Manager Specific
|
||||
.swiftpm/
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
version: 1
|
||||
builder:
|
||||
configs:
|
||||
- documentation_targets: [FloatingPanel]
|
||||
platform: ios
|
||||
@@ -0,0 +1,294 @@
|
||||
# FloatingPanel 2.0 Migration Guide
|
||||
|
||||
FloatingPanel 2.0 is the latest major release of FloatingPanel. As a major release, following Semantic Versioning conventions, 2.0 introduces API-breaking changes.
|
||||
|
||||
This guide is provided in order to ease the transition of existing applications using FloatingPanel 1.x to the latest APIs, as well as explain the design and structure of new and updated functionality.
|
||||
|
||||
## Updated Minimum Requirements
|
||||
|
||||
* Swift 5.0
|
||||
* iOS 11 (iOS 10 is still the deployment target, but not tested well)
|
||||
* Xcode 11.0
|
||||
|
||||
## Benefits of Upgrading
|
||||
|
||||
* __Top, left and right positioned panel__
|
||||
* FloatingPanel is not just a library for a bottom positioned panel, but also top, left and right positioned ones.
|
||||
* __Objective-C compatibility__
|
||||
* The entire APIs are exposed in Objective-C. So you can use them in Objective-C directly.
|
||||
* __Flexible and explicit layout customization__
|
||||
* `FloatingPanelLayout` is redesigned. There is no implicit rules to lay out a panel anymore.
|
||||
* __New spring animation without UIViewPropertyAnimator__
|
||||
* The new spring animation uses [Numeric springing](http://allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/) which is a very powerful tool for procedural animation. Therefore a library consumer is easy to modify a panel behavior by 2 paramters of the deceleration rate and response time.
|
||||
* __Handle the panel position anytime__
|
||||
* `floatingPanelDidMove(_:)` delegate method is also called while a panel is moving. The method behavior becomes same as `scrollViewDidScroll(_:)` in `UIScrollViewDelegate`. And in the method a library consumer is able to change a panel location.
|
||||
* __Update the removal interaction's invocation__
|
||||
* Now you can invoke the removal interaction at any time where you want. There is no restrictions in the library.
|
||||
* __Fix many issues depending on API design__
|
||||
* See the following sections for details.
|
||||
|
||||
## API Name Changes
|
||||
|
||||
* `FloatingPanelPosition` is now `FloatingPanelState`.
|
||||
* `FloatingPanelPosition` in v2 is used to specify a panel position(top, left, bottom and right) in a screen.
|
||||
* `FloatingPanelSurfaceView` is `SurfaceView` only in Swift.
|
||||
* `FloatingPanelBackdropView` is `BackdropView` only in Swift.
|
||||
* `FloatingPanelGrabberHandleView` is `GrabberView` only in Swift.
|
||||
* "decelerate" term is replaced with "attract" because the panel's behavior is not unidirectional, but going back and forth so that it is settled to a location.
|
||||
|
||||
## `FloatingPanelController`
|
||||
|
||||
* `layout` and `behavior` properties can be changed directly without using the delegate methods.
|
||||
|
||||
```swift
|
||||
fpc.behavior = SearchPaneliPadBehavior()
|
||||
fpc.layout = SearchPaneliPadLayout()
|
||||
fpc.invalidateLayout() // If needed
|
||||
```
|
||||
|
||||
* The second argument of `addPanel(toParent:)` changes to specify an index of subviews of a view in which a panel is added.
|
||||
|
||||
```diff
|
||||
- public func addPanel(toParent parent: UIViewController, belowView: UIView? = nil, animated: Bool = false) {
|
||||
+ public func addPanel(toParent parent: UIViewController, at viewIndex: Int = -1, animated: Bool = false) {
|
||||
```
|
||||
|
||||
* `surfaceOriginY` is now `surfaceLocation`.
|
||||
* `updateLayout` is now `invalidateLayout`.
|
||||
* The scroll tracking API is changed a bit to support multiple scroll view tracking in the future.
|
||||
* Now `untrack(scrollView:)` is used to disable the scroll tracking.
|
||||
|
||||
## `FloatingPanelControllerDelegate`
|
||||
|
||||
* `floatingPanelDidEndDragging(_ vc:willAttract:)` is added to check whether a panel will continue to move after dragging.
|
||||
* `floatingPanelDidMove(_:)` behavior changes. The method is also called in the spring animation.
|
||||
* The removal interaction delegate is updated.
|
||||
* `floatingPanel(_:shouldRemoveAt:with:)` is added to determine whether it invokes the removal interaction in any state.
|
||||
* `floatingPanelWillRemove(_:)` is added.
|
||||
* `floatingPanel(_: FloatingPanelController, layoutFor size: CGSize)` is added to respond to a layout change in regular size classes on iPad.
|
||||
|
||||
```swift
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> FloatingPanelLayout {
|
||||
if aCondition(for: size) {
|
||||
return SearchPanelLayout()
|
||||
}
|
||||
return SearchPanel2Layout()
|
||||
}
|
||||
```
|
||||
|
||||
* The `targetState` argument type of `floatingPanelWillEndDragging(_:withVelocity:targetState:)` is changed from `FloatingPanelState` to `UnsafeMutablePointer<FloatingPanelState>` to modify a target state on demand.
|
||||
|
||||
```swift
|
||||
func floatingPanelWillEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetState: UnsafeMutablePointer<FloatingPanelState>) {
|
||||
switch targetState.pointee {
|
||||
case .full:
|
||||
// do something...
|
||||
case .half:
|
||||
if aCondition {
|
||||
targetState.pointee = .tip
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* `floatingPanel(_:behaviorFor:)`
|
||||
* Please update `FloatingPanelController.behavior` directly.
|
||||
* `floatingPanel(_:shouldRecognizeSimultaneouslyWith:)`
|
||||
* Please use `FloatingPanelController.panGestureRecognizer.delegateProxy`.
|
||||
|
||||
## `FloatingPanelLayout`
|
||||
|
||||
* `position` property is added to determine a panel position.
|
||||
* `initialPosition` is now `initialState`.
|
||||
* `supportedPositions` and `insetFor(position:)` are replaced with `anchors` property.
|
||||
* `backdropAlphaFor(position:)` is now `backdropAlpha(for:)`.
|
||||
|
||||
```swift
|
||||
class SearchPanelPadLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .top
|
||||
let initialState: FloatingPanelState = .tip
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
...
|
||||
]
|
||||
}
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### New `FloatingPanelLayoutAnchoring` classes
|
||||
|
||||
The following objects adopting `FloatingPanelLayoutAnchoring` protocol are added to configure the flexible and explicit layout.
|
||||
|
||||
#### `FloatingPanelLayoutAnchor`
|
||||
|
||||
This class is used to specify a panel layout using insets from a rectangle area of the superview or safe area.
|
||||
|
||||
* `FloatingPanelFullScreenLayout` is replaced with anchors using `.superview` reference guide.
|
||||
* `FloatingPanelLayoutAnchor(fractionalInset:edge:referenceGuide:)` lets you lay out a panel at a relative position in a reference rectangle area.
|
||||
|
||||
```swift
|
||||
// Before:
|
||||
class MyPanelLayout: FloatingPanelLayout {
|
||||
var initialPosition: FloatingPanelPosition {
|
||||
return .half
|
||||
}
|
||||
|
||||
func insetFor(position: FloatingPanelPosition) -> CGFloat? {
|
||||
switch position {
|
||||
case .full: return 16.0
|
||||
case .half: return 262.0
|
||||
case .tip: return 44.0
|
||||
case .hidden: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After:
|
||||
class MyPanelLayout: FloatingPanelLayout {
|
||||
var position: FloatingPanelPosition = .bottom
|
||||
var initialState: FloatingPanelState { .half }
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .superview),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `FloatingPanelIntrinsicLayoutAnchor`
|
||||
|
||||
This class is used to specify a panel layout using offsets from the intrinsic size layout.
|
||||
|
||||
* This replaces `FloatingPanelIntrinsicLayout`.
|
||||
* This is also able to configure a fractional layout in the intrinsic size.
|
||||
|
||||
```swift
|
||||
// Before:
|
||||
class MyPanelIntrinsicLayout: FloatingPanelIntrinsicLayout {
|
||||
var initialPosition: FloatingPanelPosition {
|
||||
return .half
|
||||
}
|
||||
func insetFor(position: FloatingPanelPosition) -> CGFloat? {
|
||||
switch position {
|
||||
case .full: return 16.0
|
||||
case .half: return 262.0
|
||||
case .tip: return 44.0
|
||||
case .hidden: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After:
|
||||
class MyPanelIntrinsicLayout: FloatingPanelLayout {
|
||||
var position: FloatingPanelPosition = .bottom
|
||||
var initialState: FloatingPanelState { .full }
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(absoluteOffset: 16.0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.5, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* `.topInteractionBuffer` and `.bottomInteractionBuffer`.
|
||||
* Please control the max/min range of the motion in `floatingPanelDidMove(_:)` delegate method as below.
|
||||
|
||||
```swift
|
||||
func floatingPanelDidMove(_ fpc: FloatingPanelController) {
|
||||
if fpc.isAttracting == false {
|
||||
let loc = fpc.surfaceLocation
|
||||
let minY = fpc.surfaceLocation(for: .full).y - 6.0
|
||||
let maxY = fpc.surfaceLocation(for: .tip).y + 6.0
|
||||
fpc.surfaceLocation = CGPoint(x: loc.x, y: min(max(loc.y, minY), maxY))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `FloatingPanelBehavior`
|
||||
|
||||
* `.springDecelerationRate` and `.springResponseTime` properties are added to control the new spring effect of Numeric springing.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* `addAnimator(_:to:)`, `removeAnimator(_:from:)`
|
||||
* They are moved into `floatingPanel(_:animatorForPresentingTo:)` and `floatingPanel(_:animatorForDismissingWith:)` of `FloatingPanelControllerDelegate` because they are used for view transitions.
|
||||
* `interactionAnimator(_:to:with:)`, `moveAnimator(_:from:to:)`
|
||||
* They are removed because the animators are replaced with the new spring effect.
|
||||
* `removalVelocity`, `removalProgress`
|
||||
* They are replaced with `floatingPanel(_:shouldRemoveAt:with:)` of `FloatingPanelControllerDelegate`
|
||||
* `removalInteractionAnimator(_:with:)`
|
||||
* It is integrated with `floatingPanel(_:animatorForDismissingWith:)` of `FloatingPanelControllerDelegate`.
|
||||
|
||||
## `SurfaceView`
|
||||
|
||||
* `SurfaceAppearance` class and `SurfaceView.appearance` property are added to specify the rounding corners, shadows and background color.
|
||||
* `SurfaceView.appearance` property avoids `Ambiguous use of 'cornerRadius'` error, for instance.
|
||||
* `SurfaceAppearance` enables to apply layered box shadows into a surface to materialize it.
|
||||
|
||||
```swift
|
||||
// Before:
|
||||
fpc.surfaceView.cornerRadius = 6.0
|
||||
fpc.surfaceView.backgroundColor = .clear
|
||||
fpc.surfaceView.shadowHidden = false
|
||||
fpc.surfaceView.shadowColor = .black
|
||||
fpc.surfaceView.shadowOffset = CGSize(width: 0, height: 16)
|
||||
fpc.surfaceView.shadowRadius = 16.0
|
||||
|
||||
// After:
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 8.0
|
||||
appearance.backgroundColor = .clear
|
||||
|
||||
let shadow = SurfaceAppearance.Shadow()
|
||||
shadow.color = .black
|
||||
shadow.offset = CGSize(width: 0, height: 16)
|
||||
shadow.radius = 16
|
||||
shadow.spread = 8
|
||||
appearance.shadows = [shadow]
|
||||
|
||||
fpc.surfaceView.appearance = appearance
|
||||
```
|
||||
|
||||
* These properties are changed for the top, left and right positioned panel.
|
||||
* `grabberTopPadding` is now `grabberHandlePadding`.
|
||||
* `topGrabberBarHeight` is now `grabberAreaOffset`.
|
||||
* `grabberHandleWidth` and `grabberHandleHeight` are replaced with `grabberHandleSize`.
|
||||
|
||||
## `BackdropView`
|
||||
|
||||
* The dismissal action of the backdrop is disabled by default.
|
||||
* You can enable it to set `BackdropView.dismissalTapGestureRecognizer.isEnabled` to `true`.
|
||||
|
||||
## `FloatingPanelPanGestureRecognizer`
|
||||
|
||||
* `delegateProxy` property is added to intercept the gesture recognizer delegate.
|
||||
|
||||
```swift
|
||||
func layoutPanelForPad() {
|
||||
fpc.behavior = SearchPaneliPadBehavior()
|
||||
fpc.panGestureRecognizer.delegateProxy = self
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
* `UISpringTimingParameters(decelerationRate:frequencyResponse:initialVelocity:)` initializer is added.
|
||||
* The directory structure and file names in the Xcode project changes.
|
||||
@@ -0,0 +1,426 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 55;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
6467E8642699AC5F00565F4F /* SurfaceAppearance+phone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6467E8632699AC5F00565F4F /* SurfaceAppearance+phone.swift */; };
|
||||
6467E86A2699B19D00565F4F /* SearchPanelPhoneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6467E8692699B19D00565F4F /* SearchPanelPhoneDelegate.swift */; };
|
||||
649A122926C14D0900DAB961 /* UIHostingController+ignoreKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649A122826C14D0900DAB961 /* UIHostingController+ignoreKeyboard.swift */; };
|
||||
649A122D26C168CF00DAB961 /* View+floatingPanelGrabberHandlePadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649A122C26C168CF00DAB961 /* View+floatingPanelGrabberHandlePadding.swift */; };
|
||||
64A5B7232691323900BCAA05 /* MapsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B7222691323900BCAA05 /* MapsApp.swift */; };
|
||||
64A5B7252691323900BCAA05 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B7242691323900BCAA05 /* ContentView.swift */; };
|
||||
64A5B734269133DC00BCAA05 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A5B733269133DC00BCAA05 /* FloatingPanel.framework */; };
|
||||
64A5B735269133DC00BCAA05 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 64A5B733269133DC00BCAA05 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
64A5B738269134CA00BCAA05 /* VisualEffectBlur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B737269134CA00BCAA05 /* VisualEffectBlur.swift */; };
|
||||
64A5B73C2691469900BCAA05 /* FloatingPanelContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B73B2691469900BCAA05 /* FloatingPanelContentView.swift */; };
|
||||
64A5B73E269147DC00BCAA05 /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B73D269147DC00BCAA05 /* SearchBar.swift */; };
|
||||
64A5B7402691532400BCAA05 /* ResultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B73F2691532400BCAA05 /* ResultsList.swift */; };
|
||||
64A5B7422691541A00BCAA05 /* HostingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A5B7412691541A00BCAA05 /* HostingCell.swift */; };
|
||||
64F7E83126AD70EB00A0E0F7 /* View+floatingPanelContentInsetAdjustmentBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F7E82C26AD70EB00A0E0F7 /* View+floatingPanelContentInsetAdjustmentBehavior.swift */; };
|
||||
64F7E83226AD70EB00A0E0F7 /* View+floatingPanelContentMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F7E82D26AD70EB00A0E0F7 /* View+floatingPanelContentMode.swift */; };
|
||||
64F7E83326AD70EB00A0E0F7 /* FloatingPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F7E82E26AD70EB00A0E0F7 /* FloatingPanelView.swift */; };
|
||||
64F7E83426AD70EB00A0E0F7 /* View+floatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F7E82F26AD70EB00A0E0F7 /* View+floatingPanel.swift */; };
|
||||
64F7E83526AD70EB00A0E0F7 /* View+floatingPanelSurfaceAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F7E83026AD70EB00A0E0F7 /* View+floatingPanelSurfaceAppearance.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
64A5B736269133DC00BCAA05 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
64A5B735269133DC00BCAA05 /* FloatingPanel.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
6467E8632699AC5F00565F4F /* SurfaceAppearance+phone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SurfaceAppearance+phone.swift"; sourceTree = "<group>"; };
|
||||
6467E8692699B19D00565F4F /* SearchPanelPhoneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchPanelPhoneDelegate.swift; sourceTree = "<group>"; };
|
||||
649A122826C14D0900DAB961 /* UIHostingController+ignoreKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIHostingController+ignoreKeyboard.swift"; sourceTree = "<group>"; };
|
||||
649A122C26C168CF00DAB961 /* View+floatingPanelGrabberHandlePadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+floatingPanelGrabberHandlePadding.swift"; sourceTree = "<group>"; };
|
||||
64A5B71F2691323900BCAA05 /* Maps-SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Maps-SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
64A5B7222691323900BCAA05 /* MapsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapsApp.swift; sourceTree = "<group>"; };
|
||||
64A5B7242691323900BCAA05 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
64A5B733269133DC00BCAA05 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
64A5B737269134CA00BCAA05 /* VisualEffectBlur.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualEffectBlur.swift; sourceTree = "<group>"; };
|
||||
64A5B73B2691469900BCAA05 /* FloatingPanelContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelContentView.swift; sourceTree = "<group>"; };
|
||||
64A5B73D269147DC00BCAA05 /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
|
||||
64A5B73F2691532400BCAA05 /* ResultsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsList.swift; sourceTree = "<group>"; };
|
||||
64A5B7412691541A00BCAA05 /* HostingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingCell.swift; sourceTree = "<group>"; };
|
||||
64F7E82C26AD70EB00A0E0F7 /* View+floatingPanelContentInsetAdjustmentBehavior.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+floatingPanelContentInsetAdjustmentBehavior.swift"; sourceTree = "<group>"; };
|
||||
64F7E82D26AD70EB00A0E0F7 /* View+floatingPanelContentMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+floatingPanelContentMode.swift"; sourceTree = "<group>"; };
|
||||
64F7E82E26AD70EB00A0E0F7 /* FloatingPanelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatingPanelView.swift; sourceTree = "<group>"; };
|
||||
64F7E82F26AD70EB00A0E0F7 /* View+floatingPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+floatingPanel.swift"; sourceTree = "<group>"; };
|
||||
64F7E83026AD70EB00A0E0F7 /* View+floatingPanelSurfaceAppearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+floatingPanelSurfaceAppearance.swift"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
64A5B71C2691323900BCAA05 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
64A5B734269133DC00BCAA05 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
64A5B7162691323900BCAA05 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
64A5B7212691323900BCAA05 /* Maps */,
|
||||
64A5B7202691323900BCAA05 /* Products */,
|
||||
64A5B732269133DC00BCAA05 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
64A5B7202691323900BCAA05 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
64A5B71F2691323900BCAA05 /* Maps-SwiftUI.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
64A5B7212691323900BCAA05 /* Maps */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
64F7E82B26AD70EB00A0E0F7 /* FloatingPanel */,
|
||||
64BE55702691BBB0006D98BD /* Representable */,
|
||||
64A5B7222691323900BCAA05 /* MapsApp.swift */,
|
||||
64A5B7242691323900BCAA05 /* ContentView.swift */,
|
||||
64A5B73B2691469900BCAA05 /* FloatingPanelContentView.swift */,
|
||||
6467E8692699B19D00565F4F /* SearchPanelPhoneDelegate.swift */,
|
||||
6467E8632699AC5F00565F4F /* SurfaceAppearance+phone.swift */,
|
||||
64A5B7412691541A00BCAA05 /* HostingCell.swift */,
|
||||
64A5B73F2691532400BCAA05 /* ResultsList.swift */,
|
||||
);
|
||||
path = Maps;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
64A5B732269133DC00BCAA05 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
64A5B733269133DC00BCAA05 /* FloatingPanel.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
64BE55702691BBB0006D98BD /* Representable */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
64A5B73D269147DC00BCAA05 /* SearchBar.swift */,
|
||||
64A5B737269134CA00BCAA05 /* VisualEffectBlur.swift */,
|
||||
);
|
||||
path = Representable;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
64F7E82B26AD70EB00A0E0F7 /* FloatingPanel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
64F7E82E26AD70EB00A0E0F7 /* FloatingPanelView.swift */,
|
||||
64F7E82F26AD70EB00A0E0F7 /* View+floatingPanel.swift */,
|
||||
64F7E82C26AD70EB00A0E0F7 /* View+floatingPanelContentInsetAdjustmentBehavior.swift */,
|
||||
64F7E82D26AD70EB00A0E0F7 /* View+floatingPanelContentMode.swift */,
|
||||
64F7E83026AD70EB00A0E0F7 /* View+floatingPanelSurfaceAppearance.swift */,
|
||||
649A122C26C168CF00DAB961 /* View+floatingPanelGrabberHandlePadding.swift */,
|
||||
649A122826C14D0900DAB961 /* UIHostingController+ignoreKeyboard.swift */,
|
||||
);
|
||||
path = FloatingPanel;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
64A5B71E2691323900BCAA05 /* Maps-SwiftUI */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 64A5B72D2691323A00BCAA05 /* Build configuration list for PBXNativeTarget "Maps-SwiftUI" */;
|
||||
buildPhases = (
|
||||
64A5B71B2691323900BCAA05 /* Sources */,
|
||||
64A5B71C2691323900BCAA05 /* Frameworks */,
|
||||
64A5B71D2691323900BCAA05 /* Resources */,
|
||||
64A5B736269133DC00BCAA05 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Maps-SwiftUI";
|
||||
productName = "Maps-SwiftUI";
|
||||
productReference = 64A5B71F2691323900BCAA05 /* Maps-SwiftUI.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
64A5B7172691323900BCAA05 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1300;
|
||||
LastUpgradeCheck = 1300;
|
||||
TargetAttributes = {
|
||||
64A5B71E2691323900BCAA05 = {
|
||||
CreatedOnToolsVersion = 13.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 64A5B71A2691323900BCAA05 /* Build configuration list for PBXProject "Maps-SwiftUI" */;
|
||||
compatibilityVersion = "Xcode 13.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 64A5B7162691323900BCAA05;
|
||||
productRefGroup = 64A5B7202691323900BCAA05 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
64A5B71E2691323900BCAA05 /* Maps-SwiftUI */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
64A5B71D2691323900BCAA05 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
64A5B71B2691323900BCAA05 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6467E86A2699B19D00565F4F /* SearchPanelPhoneDelegate.swift in Sources */,
|
||||
64A5B7422691541A00BCAA05 /* HostingCell.swift in Sources */,
|
||||
64A5B738269134CA00BCAA05 /* VisualEffectBlur.swift in Sources */,
|
||||
64A5B7402691532400BCAA05 /* ResultsList.swift in Sources */,
|
||||
6467E8642699AC5F00565F4F /* SurfaceAppearance+phone.swift in Sources */,
|
||||
64F7E83226AD70EB00A0E0F7 /* View+floatingPanelContentMode.swift in Sources */,
|
||||
64A5B7252691323900BCAA05 /* ContentView.swift in Sources */,
|
||||
64A5B7232691323900BCAA05 /* MapsApp.swift in Sources */,
|
||||
64A5B73C2691469900BCAA05 /* FloatingPanelContentView.swift in Sources */,
|
||||
649A122D26C168CF00DAB961 /* View+floatingPanelGrabberHandlePadding.swift in Sources */,
|
||||
64F7E83326AD70EB00A0E0F7 /* FloatingPanelView.swift in Sources */,
|
||||
64F7E83426AD70EB00A0E0F7 /* View+floatingPanel.swift in Sources */,
|
||||
64F7E83526AD70EB00A0E0F7 /* View+floatingPanelSurfaceAppearance.swift in Sources */,
|
||||
64F7E83126AD70EB00A0E0F7 /* View+floatingPanelContentInsetAdjustmentBehavior.swift in Sources */,
|
||||
64A5B73E269147DC00BCAA05 /* SearchBar.swift in Sources */,
|
||||
649A122926C14D0900DAB961 /* UIHostingController+ignoreKeyboard.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
64A5B72B2691323A00BCAA05 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
64A5B72C2691323A00BCAA05 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
64A5B72E2691323A00BCAA05 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "example.Maps-SwiftUI";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
64A5B72F2691323A00BCAA05 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "exmaple.Maps-SwiftUI";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
64A5B71A2691323900BCAA05 /* Build configuration list for PBXProject "Maps-SwiftUI" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
64A5B72B2691323A00BCAA05 /* Debug */,
|
||||
64A5B72C2691323A00BCAA05 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
64A5B72D2691323A00BCAA05 /* Build configuration list for PBXNativeTarget "Maps-SwiftUI" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
64A5B72E2691323A00BCAA05 /* Debug */,
|
||||
64A5B72F2691323A00BCAA05 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 64A5B7172691323900BCAA05 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
import MapKit
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var region = MKCoordinateRegion(
|
||||
center: CLLocationCoordinate2D(latitude: 37.623198015869235, longitude: -122.43066818432008),
|
||||
span: MKCoordinateSpan(latitudeDelta: 0.4425100023575723, longitudeDelta: 0.28543697435880233)
|
||||
)
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Map(coordinateRegion: $region)
|
||||
.ignoresSafeArea()
|
||||
statusBarBlur
|
||||
}
|
||||
}
|
||||
|
||||
private var statusBarBlur: some View {
|
||||
GeometryReader { geometry in
|
||||
VisualEffectBlur()
|
||||
.frame(height: geometry.safeAreaInsets.top)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import SwiftUI
|
||||
|
||||
/// A proxy for exposing the methods of the floating panel controller.
|
||||
public struct FloatingPanelProxy {
|
||||
/// The associated floating panel controller.
|
||||
public weak var fpc: FloatingPanelController?
|
||||
|
||||
/// Tracks the specified scroll view to correspond with the scroll.
|
||||
///
|
||||
/// - Parameter scrollView: Specify a scroll view to continuously and
|
||||
/// seamlessly work in concert with interactions of the surface view.
|
||||
public func track(scrollView: UIScrollView) {
|
||||
fpc?.track(scrollView: scrollView)
|
||||
}
|
||||
|
||||
/// Moves the floating panel to the specified position.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - floatingPanelState: The state to move to.
|
||||
/// - animated: `true` to animate the transition to the new state; `false`
|
||||
/// otherwise.
|
||||
public func move(
|
||||
to floatingPanelState: FloatingPanelState,
|
||||
animated: Bool,
|
||||
completion: (() -> Void)? = nil
|
||||
) {
|
||||
fpc?.move(to: floatingPanelState, animated: animated, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
/// A view with an associated floating panel.
|
||||
struct FloatingPanelView<Content: View, FloatingPanelContent: View>: UIViewControllerRepresentable {
|
||||
/// A type that conforms to the `FloatingPanelControllerDelegate` protocol.
|
||||
var delegate: FloatingPanelControllerDelegate?
|
||||
|
||||
/// The behavior for determining the adjusted content offsets.
|
||||
@Environment(\.contentInsetAdjustmentBehavior) var contentInsetAdjustmentBehavior
|
||||
|
||||
/// Constants that define how a panel content fills in the surface.
|
||||
@Environment(\.contentMode) var contentMode
|
||||
|
||||
/// The floating panel grabber handle offset.
|
||||
@Environment(\.grabberHandlePadding) var grabberHandlePadding
|
||||
|
||||
/// The floating panel `surfaceView` appearance.
|
||||
@Environment(\.surfaceAppearance) var surfaceAppearance
|
||||
|
||||
/// The view builder that creates the floating panel parent view content.
|
||||
@ViewBuilder var content: Content
|
||||
|
||||
/// The view builder that creates the floating panel content.
|
||||
@ViewBuilder var floatingPanelContent: (FloatingPanelProxy) -> FloatingPanelContent
|
||||
|
||||
public func makeUIViewController(context: Context) -> UIHostingController<Content> {
|
||||
let hostingController = UIHostingController(rootView: content)
|
||||
hostingController.view.backgroundColor = nil
|
||||
// We need to wait for the current runloop cycle to complete before our
|
||||
// view is actually added (into the view hierarchy), otherwise the
|
||||
// environment is not ready yet.
|
||||
DispatchQueue.main.async {
|
||||
context.coordinator.setupFloatingPanel(hostingController)
|
||||
}
|
||||
return hostingController
|
||||
}
|
||||
|
||||
public func updateUIViewController(
|
||||
_ uiViewController: UIHostingController<Content>,
|
||||
context: Context
|
||||
) {
|
||||
context.coordinator.updateIfNeeded()
|
||||
}
|
||||
|
||||
public func makeCoordinator() -> Coordinator {
|
||||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
/// `FloatingPanelView` coordinator.
|
||||
///
|
||||
/// Responsible to setup the view hierarchy and floating panel.
|
||||
final class Coordinator {
|
||||
private let parent: FloatingPanelView<Content, FloatingPanelContent>
|
||||
private lazy var fpc = FloatingPanelController()
|
||||
|
||||
init(parent: FloatingPanelView<Content, FloatingPanelContent>) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
func setupFloatingPanel(_ parentViewController: UIViewController) {
|
||||
updateIfNeeded()
|
||||
let panelContent = parent.floatingPanelContent(FloatingPanelProxy(fpc: fpc))
|
||||
let hostingViewController = UIHostingController(
|
||||
rootView: panelContent,
|
||||
ignoresKeyboard: true
|
||||
)
|
||||
hostingViewController.view.backgroundColor = nil
|
||||
let contentViewController = UIViewController()
|
||||
contentViewController.view.addSubview(hostingViewController.view)
|
||||
fpc.set(contentViewController: contentViewController)
|
||||
fpc.addPanel(toParent: parentViewController, animated: false)
|
||||
|
||||
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
let bottomConstraint = hostingViewController.view.bottomAnchor.constraint(equalTo: contentViewController.view.bottomAnchor)
|
||||
bottomConstraint.priority = .defaultHigh
|
||||
NSLayoutConstraint.activate([
|
||||
hostingViewController.view.topAnchor.constraint(equalTo: contentViewController.view.topAnchor),
|
||||
hostingViewController.view.leadingAnchor.constraint(equalTo: contentViewController.view.leadingAnchor),
|
||||
hostingViewController.view.trailingAnchor.constraint(equalTo: contentViewController.view.trailingAnchor),
|
||||
bottomConstraint
|
||||
])
|
||||
}
|
||||
|
||||
func updateIfNeeded() {
|
||||
if fpc.contentInsetAdjustmentBehavior != parent.contentInsetAdjustmentBehavior {
|
||||
fpc.contentInsetAdjustmentBehavior = parent.contentInsetAdjustmentBehavior
|
||||
}
|
||||
if fpc.contentMode != parent.contentMode {
|
||||
fpc.contentMode = parent.contentMode
|
||||
}
|
||||
if fpc.delegate !== parent.delegate {
|
||||
fpc.delegate = parent.delegate
|
||||
}
|
||||
if fpc.surfaceView.grabberHandlePadding != parent.grabberHandlePadding {
|
||||
fpc.surfaceView.grabberHandlePadding = parent.grabberHandlePadding
|
||||
}
|
||||
if fpc.surfaceView.appearance != parent.surfaceAppearance {
|
||||
fpc.surfaceView.appearance = parent.surfaceAppearance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// This extension makes sure SwiftUI views are not affected by iOS keyboard.
|
||||
///
|
||||
/// Credits to https://steipete.me/posts/disabling-keyboard-avoidance-in-swiftui-uihostingcontroller/
|
||||
extension UIHostingController {
|
||||
public convenience init(rootView: Content, ignoresKeyboard: Bool) {
|
||||
self.init(rootView: rootView)
|
||||
|
||||
if ignoresKeyboard {
|
||||
guard let viewClass = object_getClass(view) else { return }
|
||||
|
||||
let viewSubclassName = String(
|
||||
cString: class_getName(viewClass)
|
||||
).appending("_IgnoresKeyboard")
|
||||
|
||||
if let viewSubclass = NSClassFromString(viewSubclassName) {
|
||||
object_setClass(view, viewSubclass)
|
||||
} else {
|
||||
guard
|
||||
let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String,
|
||||
let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0)
|
||||
else { return }
|
||||
|
||||
if let method = class_getInstanceMethod(
|
||||
viewClass,
|
||||
NSSelectorFromString("keyboardWillShowWithNotification:")
|
||||
) {
|
||||
let keyboardWillShow: @convention(block) (AnyObject, AnyObject) -> Void = { _, _ in }
|
||||
class_addMethod(
|
||||
viewSubclass,
|
||||
NSSelectorFromString("keyboardWillShowWithNotification:"),
|
||||
imp_implementationWithBlock(keyboardWillShow),
|
||||
method_getTypeEncoding(method)
|
||||
)
|
||||
}
|
||||
objc_registerClassPair(viewSubclass)
|
||||
object_setClass(view, viewSubclass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
/// Presents a floating panel using the given closure as its content.
|
||||
///
|
||||
/// The modifier's content view builder receives a `FloatingPanelProxy`
|
||||
/// instance; you use the proxy's methods to interact with the associated
|
||||
/// `FloatingPanelController`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - delegate: A type that conforms to the
|
||||
/// `FloatingPanelControllerDelegate` protocol. You have comprehensive
|
||||
/// control over the floating panel behavior when you use a delegate.
|
||||
/// - floatingPanelContent: The floating panel content. This view builder
|
||||
/// receives a `FloatingPanelProxy` instance that you use to interact
|
||||
/// with the `FloatingPanelController`.
|
||||
public func floatingPanel<FloatingPanelContent: View>(
|
||||
delegate: FloatingPanelControllerDelegate? = nil,
|
||||
@ViewBuilder _ floatingPanelContent: @escaping (_: FloatingPanelProxy) -> FloatingPanelContent
|
||||
) -> some View {
|
||||
FloatingPanelView(
|
||||
delegate: delegate,
|
||||
content: { self },
|
||||
floatingPanelContent: floatingPanelContent
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import SwiftUI
|
||||
|
||||
struct ContentInsetKey: EnvironmentKey {
|
||||
static var defaultValue: FloatingPanelController.ContentInsetAdjustmentBehavior = .always
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
/// The behavior for determining the adjusted content offsets.
|
||||
var contentInsetAdjustmentBehavior: FloatingPanelController.ContentInsetAdjustmentBehavior {
|
||||
get { self[ContentInsetKey.self] }
|
||||
set { self[ContentInsetKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
/// Sets the content inset adjustment behavior for floating panels within
|
||||
/// this view.
|
||||
///
|
||||
/// Use this modifier to set a specific content inset adjustment behavior
|
||||
/// for floating panel instances within a view:
|
||||
///
|
||||
/// MainView()
|
||||
/// .floatingPanel { _ in
|
||||
/// FloatingPanelContent()
|
||||
/// }
|
||||
/// .floatingPanelContentInsetAdjustmentBehavior(.never)
|
||||
///
|
||||
/// - Parameter contentInsetAdjustmentBehavior: The content inset adjustment
|
||||
/// behavior to set.
|
||||
public func floatingPanelContentInsetAdjustmentBehavior(
|
||||
_ contentInsetAdjustmentBehavior: FloatingPanelController.ContentInsetAdjustmentBehavior
|
||||
) -> some View {
|
||||
environment(\.contentInsetAdjustmentBehavior, contentInsetAdjustmentBehavior)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import SwiftUI
|
||||
|
||||
struct ContentModeKey: EnvironmentKey {
|
||||
static var defaultValue: FloatingPanelController.ContentMode = .static
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
/// Used to determine how the floating panel controller lays out the content
|
||||
/// view when the surface position changes.
|
||||
var contentMode: FloatingPanelController.ContentMode {
|
||||
get { self[ContentModeKey.self] }
|
||||
set { self[ContentModeKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
/// Sets the content mode for floating panels within this view.
|
||||
///
|
||||
/// Use this modifier to set a specific content mode for floating panel
|
||||
/// instances within a view:
|
||||
///
|
||||
/// MainView()
|
||||
/// .floatingPanel { _ in
|
||||
/// FloatingPanelContent()
|
||||
/// }
|
||||
/// .floatingPanelContentMode(.static)
|
||||
///
|
||||
/// - Parameter contentMode: The content mode to set.
|
||||
public func floatingPanelContentMode(
|
||||
_ contentMode: FloatingPanelController.ContentMode
|
||||
) -> some View {
|
||||
environment(\.contentMode, contentMode)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import SwiftUI
|
||||
|
||||
struct GrabberHandlePaddingKey: EnvironmentKey {
|
||||
static var defaultValue: CGFloat = 6.0
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
/// The offset of the grabber handle from the interactive edge.
|
||||
var grabberHandlePadding: CGFloat {
|
||||
get { self[GrabberHandlePaddingKey.self] }
|
||||
set { self[GrabberHandlePaddingKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
/// Sets the grabber handle padding for floating panels within this view.
|
||||
///
|
||||
/// Use this modifier to set a specific padding to floating panel instances
|
||||
/// within a view:
|
||||
///
|
||||
/// MainView()
|
||||
/// .floatingPanel { _ in
|
||||
/// FloatingPanelContent()
|
||||
/// }
|
||||
/// .floatingPanelGrabberHandlePadding(16)
|
||||
///
|
||||
/// - Parameter padding: The grabber handle padding to set.
|
||||
public func floatingPanelGrabberHandlePadding(
|
||||
_ padding: CGFloat
|
||||
) -> some View {
|
||||
environment(\.grabberHandlePadding, padding)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import SwiftUI
|
||||
|
||||
struct SurfaceAppearanceKey: EnvironmentKey {
|
||||
static var defaultValue = SurfaceAppearance()
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
/// The appearance of a surface view.
|
||||
var surfaceAppearance: SurfaceAppearance {
|
||||
get { self[SurfaceAppearanceKey.self] }
|
||||
set { self[SurfaceAppearanceKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
/// Sets the surface appearance for floating panels within this view.
|
||||
///
|
||||
/// Use this modifier to set a specific surface appearance for floating
|
||||
/// panel instances within a view:
|
||||
///
|
||||
/// MainView()
|
||||
/// .floatingPanel { _ in
|
||||
/// FloatingPanelContent()
|
||||
/// }
|
||||
/// .floatingPanelSurfaceAppearance(.transparent)
|
||||
///
|
||||
/// extension SurfaceAppearance {
|
||||
/// static var transparent: SurfaceAppearance {
|
||||
/// let appearance = SurfaceAppearance()
|
||||
/// appearance.backgroundColor = .clear
|
||||
/// return appearance
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// - Parameter surfaceAppearance: The surface appearance to set.
|
||||
public func floatingPanelSurfaceAppearance(
|
||||
_ surfaceAppearance: SurfaceAppearance
|
||||
) -> some View {
|
||||
environment(\.surfaceAppearance, surfaceAppearance)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct FloatingPanelContentView: View {
|
||||
@State private var searchText = ""
|
||||
@State private var isShowingCancelButton = false
|
||||
var proxy: FloatingPanelProxy
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
searchBar
|
||||
resultsList
|
||||
}
|
||||
// 👇🏻 for the floating panel grabber handle.
|
||||
.padding(.top, 6)
|
||||
.background(
|
||||
VisualEffectBlur(blurStyle: .systemMaterial)
|
||||
// ⚠️ If the `VisualEffectBlur` view receives taps, it's going
|
||||
// to mess up with the whole panel and render it
|
||||
// non-interactive, make sure it never receives any taps.
|
||||
.allowsHitTesting(false)
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
||||
var searchBar: some View {
|
||||
SearchBar(
|
||||
"Search for a place or address",
|
||||
text: $searchText,
|
||||
isShowingCancelButton: $isShowingCancelButton
|
||||
) { isFocused in
|
||||
proxy.move(to: isFocused ? .full : .half, animated: true)
|
||||
isShowingCancelButton = isFocused
|
||||
} onCancel: {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
}
|
||||
|
||||
var resultsList: some View {
|
||||
ResultsList(onScrollViewCreated: proxy.track(scrollView:))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A `UITableViewCell` that accepts a SwiftUI view as its content.
|
||||
///
|
||||
/// Credits to https://noahgilmore.com/blog/swiftui-self-sizing-cells/ .
|
||||
public final class HostingCell<Content: View>: UITableViewCell {
|
||||
private let hostingController = UIHostingController<Content?>(
|
||||
rootView: nil,
|
||||
ignoresKeyboard: true
|
||||
)
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
hostingController.view.backgroundColor = nil
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func set(rootView: Content, parentController: UIViewController) {
|
||||
hostingController.rootView = rootView
|
||||
hostingController.view.invalidateIntrinsicContentSize()
|
||||
|
||||
let requiresControllerMove = hostingController.parent != parentController
|
||||
if requiresControllerMove {
|
||||
parentController.addChild(hostingController)
|
||||
}
|
||||
|
||||
if !contentView.subviews.contains(hostingController.view) {
|
||||
contentView.addSubview(hostingController.view)
|
||||
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addConstraints([
|
||||
hostingController.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||
hostingController.view.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
hostingController.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||
hostingController.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
if requiresControllerMove {
|
||||
hostingController.didMove(toParent: parentController)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct MapsApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.floatingPanel(delegate: SearchPanelPhoneDelegate()) { proxy in
|
||||
FloatingPanelContentView(proxy: proxy)
|
||||
}
|
||||
.floatingPanelSurfaceAppearance(.phone)
|
||||
.floatingPanelContentMode(.fitToBounds)
|
||||
.floatingPanelContentInsetAdjustmentBehavior(.never)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// UIKit's `UISearchBar`brought to SwiftUI.
|
||||
public struct SearchBar: UIViewRepresentable {
|
||||
var title: String
|
||||
@Binding var text: String
|
||||
@Binding var isShowingCancelButton: Bool
|
||||
var onEditingChanged: (Bool) -> Void
|
||||
var onCancel: () -> Void
|
||||
|
||||
public init(
|
||||
_ title: String = "",
|
||||
text: Binding<String>,
|
||||
isShowingCancelButton: Binding<Bool>,
|
||||
onEditingChanged: @escaping (Bool) -> Void = { _ in },
|
||||
onCancel: @escaping () -> Void
|
||||
) {
|
||||
self.title = title
|
||||
self._text = text
|
||||
self._isShowingCancelButton = isShowingCancelButton
|
||||
self.onEditingChanged = onEditingChanged
|
||||
self.onCancel = onCancel
|
||||
}
|
||||
|
||||
public func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
|
||||
let searchBar = UISearchBar(frame: .zero)
|
||||
searchBar.searchBarStyle = .minimal
|
||||
searchBar.isTranslucent = true
|
||||
searchBar.placeholder = title
|
||||
searchBar.delegate = context.coordinator
|
||||
searchBar.autocapitalizationType = .none
|
||||
return searchBar
|
||||
}
|
||||
|
||||
public func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
|
||||
uiView.text = text
|
||||
uiView.placeholder = title
|
||||
uiView.setShowsCancelButton(isShowingCancelButton, animated: true)
|
||||
}
|
||||
|
||||
public func makeCoordinator() -> SearchBar.Coordinator {
|
||||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
public class Coordinator: NSObject, UISearchBarDelegate {
|
||||
var parent: SearchBar
|
||||
|
||||
init(parent: SearchBar) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
|
||||
parent.text = searchText
|
||||
}
|
||||
|
||||
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
parent.onEditingChanged(true)
|
||||
}
|
||||
|
||||
public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
|
||||
searchBar.resignFirstResponder()
|
||||
}
|
||||
|
||||
public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
|
||||
parent.onEditingChanged(false)
|
||||
}
|
||||
|
||||
public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
|
||||
parent.onCancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@available(iOS, introduced: 13, deprecated: 15, message: "Use iOS 15 material API.")
|
||||
public struct VisualEffectBlur<Content: View>: UIViewRepresentable {
|
||||
var blurStyle: UIBlurEffect.Style = .systemMaterial
|
||||
var vibrancyStyle: UIVibrancyEffectStyle? = nil
|
||||
@ViewBuilder var content: Content
|
||||
|
||||
public func makeUIView(context: Context) -> UIVisualEffectView {
|
||||
context.coordinator.blurView
|
||||
}
|
||||
|
||||
public func updateUIView(_ view: UIVisualEffectView, context: Context) {
|
||||
context.coordinator.update(
|
||||
content: content,
|
||||
blurStyle: blurStyle,
|
||||
vibrancyStyle: vibrancyStyle
|
||||
)
|
||||
}
|
||||
|
||||
public func makeCoordinator() -> Coordinator {
|
||||
Coordinator(content: content)
|
||||
}
|
||||
|
||||
public class Coordinator {
|
||||
let blurView = UIVisualEffectView()
|
||||
let vibrancyView = UIVisualEffectView()
|
||||
let hostingController: UIHostingController<Content>
|
||||
|
||||
init(content: Content) {
|
||||
hostingController = UIHostingController(rootView: content)
|
||||
hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
hostingController.view.backgroundColor = nil
|
||||
blurView.contentView.addSubview(vibrancyView)
|
||||
|
||||
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
vibrancyView.contentView.addSubview(hostingController.view)
|
||||
vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
}
|
||||
|
||||
func update(content: Content, blurStyle: UIBlurEffect.Style, vibrancyStyle: UIVibrancyEffectStyle?) {
|
||||
hostingController.rootView = content
|
||||
|
||||
let blurEffect = UIBlurEffect(style: blurStyle)
|
||||
blurView.effect = blurEffect
|
||||
|
||||
if let vibrancyStyle = vibrancyStyle {
|
||||
vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect, style: vibrancyStyle)
|
||||
} else {
|
||||
vibrancyView.effect = nil
|
||||
}
|
||||
|
||||
hostingController.view.setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension VisualEffectBlur where Content == EmptyView {
|
||||
init(
|
||||
blurStyle: UIBlurEffect.Style = .systemMaterial,
|
||||
vibrancyStyle: UIVibrancyEffectStyle? = nil
|
||||
) {
|
||||
self.init(blurStyle: blurStyle, vibrancyStyle: vibrancyStyle) {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ResultsList: UIViewControllerRepresentable {
|
||||
var onScrollViewCreated: (_ scrollView: UIScrollView) -> Void
|
||||
|
||||
func makeUIViewController(
|
||||
context: Context
|
||||
) -> ResultsTableViewController {
|
||||
let rtvc = ResultsTableViewController()
|
||||
onScrollViewCreated(rtvc.tableView)
|
||||
return rtvc
|
||||
}
|
||||
|
||||
func updateUIViewController(
|
||||
_ uiViewController: ResultsTableViewController,
|
||||
context: Context
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
final class ResultsTableViewController: UITableViewController {
|
||||
private let reuseIdentifier = "HostingCell<ResultListCell>"
|
||||
|
||||
private enum Section: CaseIterable {
|
||||
case main
|
||||
}
|
||||
|
||||
private struct TableViewItem: Hashable {
|
||||
let color: Color
|
||||
let symbolName: String
|
||||
let title: String
|
||||
let description: String
|
||||
}
|
||||
|
||||
private var dataSource: UITableViewDiffableDataSource<Section, TableViewItem>?
|
||||
|
||||
// MARK: Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.backgroundColor = nil
|
||||
tableView.register(HostingCell<ResultListCell>.self, forCellReuseIdentifier: reuseIdentifier)
|
||||
configureDataSource()
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
private func configureDataSource() {
|
||||
dataSource = UITableViewDiffableDataSource
|
||||
<Section, TableViewItem>(tableView: tableView) { [weak self] tableView, _, tableItem -> UITableViewCell? in
|
||||
self?.tableView(tableView, cellForTableViewItem: tableItem)
|
||||
}
|
||||
tableView.dataSource = dataSource
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, TableViewItem>()
|
||||
snapshot.appendSections([.main])
|
||||
let results: [TableViewItem] = (1...100).map {
|
||||
TableViewItem(
|
||||
color: Color(red: 255 / 255.0, green: 94 / 255.0 , blue: 94 / 255.0),
|
||||
symbolName: "heart.fill",
|
||||
title: "Favorites",
|
||||
description: "\($0) Places"
|
||||
)
|
||||
}
|
||||
snapshot.appendItems(results, toSection: .main)
|
||||
dataSource?.apply(snapshot, animatingDifferences: false)
|
||||
}
|
||||
|
||||
private func tableView(
|
||||
_ tableView: UITableView,
|
||||
cellForTableViewItem tableViewItem: TableViewItem
|
||||
) -> UITableViewCell {
|
||||
let cell: HostingCell<ResultListCell> = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) as! HostingCell<ResultListCell>
|
||||
setupResultTableViewCell(
|
||||
cell,
|
||||
color: tableViewItem.color,
|
||||
symbolName: tableViewItem.symbolName,
|
||||
title: tableViewItem.title,
|
||||
description: tableViewItem.description
|
||||
)
|
||||
return cell
|
||||
}
|
||||
|
||||
private func setupResultTableViewCell(
|
||||
_ cell: HostingCell<ResultListCell>,
|
||||
color: Color,
|
||||
symbolName: String,
|
||||
title: String,
|
||||
description: String
|
||||
) {
|
||||
cell.set(
|
||||
rootView: ResultListCell(
|
||||
color: color,
|
||||
symbolName: symbolName,
|
||||
title: title,
|
||||
description: description
|
||||
),
|
||||
parentController: self
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
didSelectRowAt indexPath: IndexPath
|
||||
) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
struct ResultListCell: View {
|
||||
let color: Color
|
||||
let symbolName: String
|
||||
let title: String
|
||||
let description: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Image(systemName: symbolName)
|
||||
.foregroundColor(.white)
|
||||
.font(.headline)
|
||||
.padding(8)
|
||||
.background(Circle().fill(color))
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(title)
|
||||
.font(.system(size: 20, weight: .bold))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text(description)
|
||||
.font(.system(size: 13))
|
||||
.foregroundColor(Color(.secondaryLabel))
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import UIKit
|
||||
|
||||
final class SearchPanelPhoneDelegate: FloatingPanelControllerDelegate {
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
|
||||
if vc.state == .full {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
|
||||
extension FloatingPanel.SurfaceAppearance {
|
||||
static var phone: SurfaceAppearance {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerCurve = .continuous
|
||||
appearance.cornerRadius = 8.0
|
||||
appearance.backgroundColor = .clear
|
||||
return appearance
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,18 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
543844BD23D2BE2000D5EDE4 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 543844BC23D2BE2000D5EDE4 /* MapKit.framework */; };
|
||||
549A5F59244673FE0025F312 /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549A5F58244673FE0025F312 /* SearchViewController.swift */; };
|
||||
549D23D2233C77D5008EF4D7 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23D1233C77D5008EF4D7 /* FloatingPanel.framework */; };
|
||||
549D23D3233C77D5008EF4D7 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23D1233C77D5008EF4D7 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
54B5112A216C3D840033A6F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B51129216C3D840033A6F3 /* AppDelegate.swift */; };
|
||||
54B5112C216C3D840033A6F3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B5112B216C3D840033A6F3 /* ViewController.swift */; };
|
||||
54B5112C216C3D840033A6F3 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B5112B216C3D840033A6F3 /* MainViewController.swift */; };
|
||||
54B5112F216C3D840033A6F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 54B5112D216C3D840033A6F3 /* Main.storyboard */; };
|
||||
54B51131216C3D860033A6F3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 54B51130216C3D860033A6F3 /* Assets.xcassets */; };
|
||||
54B51134216C3D860033A6F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 54B51132216C3D860033A6F3 /* LaunchScreen.storyboard */; };
|
||||
54B5113F216C407F0033A6F3 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54B5113E216C407F0033A6F3 /* FloatingPanel.framework */; };
|
||||
54B51140216C407F0033A6F3 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 54B5113E216C407F0033A6F3 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
54E26CB624A989090066C720 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E26CB524A989090066C720 /* Utils.swift */; };
|
||||
54E26CB824A98E310066C720 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E26CB724A98E310066C720 /* DetailViewController.swift */; };
|
||||
5D82A6A728D18422006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6A628D1841E006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -23,7 +28,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
54B51140216C407F0033A6F3 /* FloatingPanel.framework in Embed Frameworks */,
|
||||
549D23D3233C77D5008EF4D7 /* FloatingPanel.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -31,14 +36,19 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
543844BC23D2BE2000D5EDE4 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
|
||||
549A5F58244673FE0025F312 /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = "<group>"; };
|
||||
549D23D1233C77D5008EF4D7 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
54B51126216C3D840033A6F3 /* Maps.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Maps.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
54B51129216C3D840033A6F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
54B5112B216C3D840033A6F3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
54B5112B216C3D840033A6F3 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
54B5112E216C3D840033A6F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
54B51130216C3D860033A6F3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
54B51133216C3D860033A6F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
54B51135216C3D860033A6F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
54B5113E216C407F0033A6F3 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
54E26CB524A989090066C720 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
|
||||
54E26CB724A98E310066C720 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
|
||||
5D82A6A628D1841E006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -46,19 +56,31 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54B5113F216C407F0033A6F3 /* FloatingPanel.framework in Frameworks */,
|
||||
543844BD23D2BE2000D5EDE4 /* MapKit.framework in Frameworks */,
|
||||
5D82A6A728D18422006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
549D23D2233C77D5008EF4D7 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
543844BB23D2BE1F00D5EDE4 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6A628D1841E006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
543844BC23D2BE2000D5EDE4 /* MapKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
54B5111D216C3D840033A6F3 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54B5113E216C407F0033A6F3 /* FloatingPanel.framework */,
|
||||
549D23D1233C77D5008EF4D7 /* FloatingPanel.framework */,
|
||||
54B51128216C3D840033A6F3 /* Maps */,
|
||||
54B51127216C3D840033A6F3 /* Products */,
|
||||
543844BB23D2BE1F00D5EDE4 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -73,11 +95,14 @@
|
||||
54B51128216C3D840033A6F3 /* Maps */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54B51129216C3D840033A6F3 /* AppDelegate.swift */,
|
||||
54B5112B216C3D840033A6F3 /* ViewController.swift */,
|
||||
54B5112D216C3D840033A6F3 /* Main.storyboard */,
|
||||
54B51130216C3D860033A6F3 /* Assets.xcassets */,
|
||||
54B51132216C3D860033A6F3 /* LaunchScreen.storyboard */,
|
||||
54B5112D216C3D840033A6F3 /* Main.storyboard */,
|
||||
54B51129216C3D840033A6F3 /* AppDelegate.swift */,
|
||||
54B5112B216C3D840033A6F3 /* MainViewController.swift */,
|
||||
549A5F58244673FE0025F312 /* SearchViewController.swift */,
|
||||
54E26CB724A98E310066C720 /* DetailViewController.swift */,
|
||||
54E26CB524A989090066C720 /* Utils.swift */,
|
||||
54B51135216C3D860033A6F3 /* Info.plist */,
|
||||
);
|
||||
path = Maps;
|
||||
@@ -111,7 +136,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1000;
|
||||
LastUpgradeCheck = 1000;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = scenee;
|
||||
TargetAttributes = {
|
||||
54B51125216C3D840033A6F3 = {
|
||||
@@ -155,8 +180,11 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54B5112C216C3D840033A6F3 /* ViewController.swift in Sources */,
|
||||
549A5F59244673FE0025F312 /* SearchViewController.swift in Sources */,
|
||||
54B5112C216C3D840033A6F3 /* MainViewController.swift in Sources */,
|
||||
54E26CB824A98E310066C720 /* DetailViewController.swift in Sources */,
|
||||
54B5112A216C3D840033A6F3 /* AppDelegate.swift in Sources */,
|
||||
54E26CB624A989090066C720 /* Utils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -208,6 +236,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -269,6 +298,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -303,16 +333,20 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Maps/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.Maps;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Maps;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -322,16 +356,20 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Maps/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.Maps;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Maps;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,8 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -38,8 +36,8 @@
|
||||
ReferencedContainer = "container:Maps.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -63,8 +61,6 @@
|
||||
ReferencedContainer = "container:Maps.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Maps
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/10/09.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina5_9" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Maps" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="BYZ-38-t0r" customClass="MainViewController" customModule="Maps" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="5Jw-n2-Cpw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
</mapView>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d9i-3g-8Ja">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="59"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="lMa-xa-AVV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="59"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<blurEffect style="light"/>
|
||||
<blurEffect style="prominent"/>
|
||||
</visualEffectView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="5Jw-n2-Cpw" firstAttribute="trailing" secondItem="8bC-Xf-vdC" secondAttribute="trailing" id="1Fg-Be-qfh"/>
|
||||
@@ -41,7 +40,6 @@
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="top" secondItem="d9i-3g-8Ja" secondAttribute="bottom" id="Y1G-hr-aEX"/>
|
||||
<constraint firstItem="d9i-3g-8Ja" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="diB-Ij-HN3"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="mapView" destination="5Jw-n2-Cpw" id="WVC-rU-mLe"/>
|
||||
@@ -51,33 +49,33 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="136.80000000000001" y="133.00492610837438"/>
|
||||
</scene>
|
||||
<!--Search Panel View Controller-->
|
||||
<!--Search View Controller-->
|
||||
<scene sceneID="kXy-li-p3C">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="SearchPanel" useStoryboardIdentifierAsRestorationIdentifier="YES" id="0S1-Lk-JgE" customClass="SearchPanelViewController" customModule="Maps" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="SearchViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="0S1-Lk-JgE" customClass="SearchViewController" customModule="Maps" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ncl-E9-yRn">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ye3-uU-bq3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="ED1-gT-FBj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<searchBar contentMode="redraw" searchBarStyle="minimal" translatesAutoresizingMaskIntoConstraints="NO" id="Zcj-SE-gb8">
|
||||
<rect key="frame" x="0.0" y="6" width="375" height="56"/>
|
||||
<rect key="frame" x="0.0" y="6" width="393" height="56"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</searchBar>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="D7r-re-InH">
|
||||
<rect key="frame" x="0.0" y="66" width="375" height="712"/>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="D7r-re-InH">
|
||||
<rect key="frame" x="0.0" y="66" width="393" height="786"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="u28-LY-hIh" customClass="SearchHeaderView" customModule="Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="116"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="116"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" baselineRelativeArrangement="YES" translatesAutoresizingMaskIntoConstraints="NO" id="era-8w-yA1">
|
||||
<rect key="frame" x="24" y="10.666666666666664" width="327" height="97.333333333333343"/>
|
||||
<rect key="frame" x="24" y="10.666666666666664" width="345" height="97.333333333333343"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="auI-1v-Yfk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="60" height="97.333333333333329"/>
|
||||
@@ -98,7 +96,7 @@
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="0vd-sD-XKv">
|
||||
<rect key="frame" x="89" y="0.0" width="60" height="97.333333333333329"/>
|
||||
<rect key="frame" x="95" y="0.0" width="60" height="97.333333333333329"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="shopping" translatesAutoresizingMaskIntoConstraints="NO" id="xcm-St-HAo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
|
||||
@@ -118,7 +116,7 @@
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="Jd8-YL-b5s">
|
||||
<rect key="frame" x="178" y="0.0" width="60" height="97.333333333333329"/>
|
||||
<rect key="frame" x="190" y="0.0" width="60" height="97.333333333333329"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="fun" translatesAutoresizingMaskIntoConstraints="NO" id="bMJ-Jn-Gi8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
|
||||
@@ -138,7 +136,7 @@
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="dTL-e1-Arz">
|
||||
<rect key="frame" x="267" y="0.0" width="60" height="97.333333333333329"/>
|
||||
<rect key="frame" x="285" y="0.0" width="60" height="97.333333333333329"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="travel" translatesAutoresizingMaskIntoConstraints="NO" id="8h3-fo-pC3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
|
||||
@@ -170,10 +168,10 @@
|
||||
</view>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="Cell" rowHeight="70" id="LzC-B9-Adb" customClass="SearchCell" customModule="Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="144" width="375" height="70"/>
|
||||
<rect key="frame" x="0.0" y="166" width="393" height="70"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="LzC-B9-Adb" id="evr-60-laS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="69.666666666666671"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="70"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="like" translatesAutoresizingMaskIntoConstraints="NO" id="GEk-yE-lLq">
|
||||
@@ -185,16 +183,16 @@
|
||||
</constraints>
|
||||
</imageView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="2" translatesAutoresizingMaskIntoConstraints="NO" id="Gfl-Oy-rsy">
|
||||
<rect key="frame" x="57" y="11.999999999999996" width="303" height="45.666666666666657"/>
|
||||
<rect key="frame" x="57" y="12" width="321" height="46"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Favorites" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Spf-8L-Ne6">
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" height="22"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="321" height="22"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0 Places" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gyo-3V-7U8">
|
||||
<rect key="frame" x="0.0" y="24" width="303" height="21.666666666666671"/>
|
||||
<rect key="frame" x="0.0" y="24" width="321" height="22"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.57647058819999997" green="0.57647058819999997" blue="0.57647058819999997" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -232,27 +230,66 @@
|
||||
<constraint firstItem="Zcj-SE-gb8" firstAttribute="leading" secondItem="ED1-gT-FBj" secondAttribute="leading" id="wMb-L2-Z0W"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<blurEffect style="extraLight"/>
|
||||
<blurEffect style="prominent"/>
|
||||
</visualEffectView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="G74-X7-Za8"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Ye3-uU-bq3" firstAttribute="leading" secondItem="G74-X7-Za8" secondAttribute="leading" id="Kr2-sU-ZWZ"/>
|
||||
<constraint firstItem="Ye3-uU-bq3" firstAttribute="bottom" secondItem="G74-X7-Za8" secondAttribute="bottom" id="aWM-s3-3o4"/>
|
||||
<constraint firstItem="Ye3-uU-bq3" firstAttribute="bottom" secondItem="Ncl-E9-yRn" secondAttribute="bottom" id="aWM-s3-3o4"/>
|
||||
<constraint firstItem="Ye3-uU-bq3" firstAttribute="trailing" secondItem="G74-X7-Za8" secondAttribute="trailing" id="fEL-8y-Acc"/>
|
||||
<constraint firstItem="Ye3-uU-bq3" firstAttribute="top" secondItem="Ncl-E9-yRn" secondAttribute="top" id="w77-ba-FrJ"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="G74-X7-Za8"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="searchBar" destination="Zcj-SE-gb8" id="BH7-Gy-RG5"/>
|
||||
<outlet property="tableView" destination="D7r-re-InH" id="nRN-fY-b8j"/>
|
||||
<outlet property="visualEffectView" destination="Ye3-uU-bq3" id="rS6-Mq-OKs"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="EqR-Hp-zhc" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="789.60000000000002" y="133.5832083958021"/>
|
||||
</scene>
|
||||
<!--Detail View Controller-->
|
||||
<scene sceneID="5tH-Ya-PzB">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="DetailViewController" id="Tp2-MF-IFz" customClass="DetailViewController" customModule="Maps" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="FmO-AT-4Y7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c3d-2e-0b1">
|
||||
<rect key="frame" x="-1" y="-1" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="9fL-a5-0LS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="kP7-56-wlG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="kP7-56-wlG" firstAttribute="leading" secondItem="9fL-a5-0LS" secondAttribute="leading" id="6gf-GO-cnv"/>
|
||||
<constraint firstAttribute="bottom" secondItem="kP7-56-wlG" secondAttribute="bottom" id="WrH-tz-UQF"/>
|
||||
<constraint firstItem="kP7-56-wlG" firstAttribute="top" secondItem="9fL-a5-0LS" secondAttribute="top" id="aJk-bz-lVc"/>
|
||||
<constraint firstAttribute="trailing" secondItem="kP7-56-wlG" secondAttribute="trailing" id="sE0-9V-Rot"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<blurEffect style="extraLight"/>
|
||||
</visualEffectView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="ctv-Dd-JUc"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="EDp-D2-xcT" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1447" y="133"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="food" width="60" height="60"/>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
class DetailViewController: UIViewController {
|
||||
var item: LocationItem?
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import MapKit
|
||||
import FloatingPanel
|
||||
|
||||
class MainViewController: UIViewController {
|
||||
typealias PanelDelegate = FloatingPanelControllerDelegate & UIGestureRecognizerDelegate
|
||||
|
||||
// Search Panel
|
||||
lazy var fpc = FloatingPanelController()
|
||||
lazy var fpcDelegate: PanelDelegate =
|
||||
(traitCollection.userInterfaceIdiom == .pad) ? SearchPanelPadDelegate(owner: self) : SearchPanelPhoneDelegate(owner: self)
|
||||
lazy var searchVC =
|
||||
storyboard?.instantiateViewController(withIdentifier: "SearchViewController") as! SearchViewController
|
||||
|
||||
// Detail Panel
|
||||
lazy var detailFpc = FloatingPanelController()
|
||||
lazy var detailFpcDelegate: PanelDelegate =
|
||||
(traitCollection.userInterfaceIdiom == .pad) ? DetailPanelPadDelegate(owner: self) : DetailPanelPhoneDelegate(owner: self)
|
||||
lazy var detailVC =
|
||||
storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
|
||||
|
||||
@IBOutlet weak var mapView: MKMapView!
|
||||
}
|
||||
|
||||
extension MainViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
fpc.contentMode = .fitToBounds
|
||||
fpc.delegate = fpcDelegate
|
||||
fpc.set(contentViewController: searchVC)
|
||||
fpc.track(scrollView: searchVC.tableView)
|
||||
|
||||
detailFpc.isRemovalInteractionEnabled = true
|
||||
detailFpc.set(contentViewController: detailVC)
|
||||
|
||||
switch traitCollection.userInterfaceIdiom {
|
||||
case .pad:
|
||||
layoutPanelForPad()
|
||||
default:
|
||||
layoutPanelForPhone()
|
||||
}
|
||||
|
||||
setUpMapView()
|
||||
setUpSearchView()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
// Must be here
|
||||
searchVC.searchBar.delegate = self
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
tearDownMapView()
|
||||
}
|
||||
}
|
||||
|
||||
extension MainViewController {
|
||||
func layoutPanelForPad() {
|
||||
fpc.behavior = SearchPaneliPadBehavior()
|
||||
fpc.panGestureRecognizer.delegateProxy = fpcDelegate
|
||||
|
||||
// Not use addPanel(toParent:) because of the Auto Layout configuration of fpc.view.
|
||||
view.addSubview(fpc.view)
|
||||
addChild(fpc)
|
||||
fpc.view.frame = view.bounds // Needed for a correct safe area configuration
|
||||
fpc.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
fpc.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0),
|
||||
fpc.view.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0.0 ),
|
||||
fpc.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0),
|
||||
fpc.view.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: 0.0),
|
||||
])
|
||||
fpc.show(animated: false) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.didMove(toParent: self)
|
||||
}
|
||||
|
||||
[fpc, detailFpc].forEach { $0.setAppearanceForPad() }
|
||||
}
|
||||
|
||||
func layoutPanelForPhone() {
|
||||
fpc.track(scrollView: searchVC.tableView) // Only track the table view on iPhone
|
||||
fpc.addPanel(toParent: self, animated: true)
|
||||
|
||||
[fpc, detailFpc].forEach { $0.setAppearanceForPhone()}
|
||||
}
|
||||
}
|
||||
|
||||
extension FloatingPanelController {
|
||||
func setAppearanceForPhone() {
|
||||
let appearance = SurfaceAppearance()
|
||||
if #available(iOS 13.0, *) {
|
||||
appearance.cornerCurve = .continuous
|
||||
}
|
||||
appearance.cornerRadius = 8.0
|
||||
appearance.backgroundColor = .clear
|
||||
surfaceView.appearance = appearance
|
||||
}
|
||||
|
||||
func setAppearanceForPad() {
|
||||
view.clipsToBounds = false
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 8.0
|
||||
let shadow = SurfaceAppearance.Shadow()
|
||||
shadow.color = UIColor.black
|
||||
shadow.offset = CGSize(width: 0, height: 16)
|
||||
shadow.radius = 16
|
||||
shadow.spread = 8
|
||||
appearance.shadows = [shadow]
|
||||
appearance.backgroundColor = .clear
|
||||
surfaceView.appearance = appearance
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UISearchBarDelegate
|
||||
|
||||
extension MainViewController: UISearchBarDelegate {
|
||||
func activate(searchBar: UISearchBar) {
|
||||
searchBar.showsCancelButton = true
|
||||
searchVC.showHeader(animated: true)
|
||||
searchVC.tableView.alpha = 1.0
|
||||
detailVC.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
func deactivate(searchBar: UISearchBar) {
|
||||
searchBar.resignFirstResponder()
|
||||
searchBar.showsCancelButton = false
|
||||
searchVC.hideHeader(animated: true)
|
||||
}
|
||||
|
||||
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
|
||||
deactivate(searchBar: searchBar)
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.fpc.move(to: .half, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
activate(searchBar: searchBar)
|
||||
UIView.animate(withDuration: 0.25) { [weak self] in
|
||||
self?.fpc.move(to: .full, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - iPhone
|
||||
|
||||
class SearchPanelPhoneDelegate: NSObject, FloatingPanelControllerDelegate, UIGestureRecognizerDelegate {
|
||||
unowned let owner: MainViewController
|
||||
|
||||
init(owner: MainViewController) {
|
||||
self.owner = owner
|
||||
}
|
||||
|
||||
func floatingPanel(
|
||||
_ fpc: FloatingPanelController,
|
||||
shouldAllowToScroll scrollView: UIScrollView,
|
||||
in state: FloatingPanelState
|
||||
) -> Bool {
|
||||
return state == .full || state == .half
|
||||
}
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
switch newCollection.verticalSizeClass {
|
||||
case .compact:
|
||||
let appearance = vc.surfaceView.appearance
|
||||
appearance.borderWidth = 1.0 / owner.traitCollection.displayScale
|
||||
appearance.borderColor = UIColor.black.withAlphaComponent(0.2)
|
||||
vc.surfaceView.appearance = appearance
|
||||
return SearchPanelLandscapeLayout()
|
||||
default:
|
||||
let appearance = vc.surfaceView.appearance
|
||||
appearance.borderWidth = 0.0
|
||||
appearance.borderColor = nil
|
||||
vc.surfaceView.appearance = appearance
|
||||
return FloatingPanelBottomLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelDidMove(_ vc: FloatingPanelController) {
|
||||
debugPrint("surfaceLocation: ", vc.surfaceLocation)
|
||||
let loc = vc.surfaceLocation
|
||||
|
||||
if vc.isAttracting == false {
|
||||
let minY = vc.surfaceLocation(for: .full).y - 6.0
|
||||
let maxY = vc.surfaceLocation(for: .tip).y + 6.0
|
||||
vc.surfaceLocation = CGPoint(x: loc.x, y: min(max(loc.y, minY), maxY))
|
||||
}
|
||||
|
||||
let tipY = vc.surfaceLocation(for: .tip).y
|
||||
if loc.y > tipY - 44.0 {
|
||||
let progress = max(0.0, min((tipY - loc.y) / 44.0, 1.0))
|
||||
owner.searchVC.tableView.alpha = progress
|
||||
} else {
|
||||
owner.searchVC.tableView.alpha = 1.0
|
||||
}
|
||||
debugPrint("NearbyState : ",vc.nearbyState)
|
||||
}
|
||||
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
|
||||
if vc.state == .full {
|
||||
owner.searchVC.searchBar.showsCancelButton = false
|
||||
owner.searchVC.searchBar.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelWillEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetState: UnsafeMutablePointer<FloatingPanelState>) {
|
||||
if targetState.pointee != .full {
|
||||
owner.searchVC.hideHeader(animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SearchPanelLandscapeLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .tip
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
return [
|
||||
surfaceView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 8.0),
|
||||
surfaceView.widthAnchor.constraint(equalToConstant: 291),
|
||||
]
|
||||
}
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
class DetailPanelPhoneDelegate: NSObject, FloatingPanelControllerDelegate, UIGestureRecognizerDelegate {
|
||||
unowned let owner: MainViewController
|
||||
|
||||
init(owner: MainViewController) {
|
||||
self.owner = owner
|
||||
}
|
||||
}
|
||||
|
||||
class DetailPanelPhoneLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - iPad
|
||||
|
||||
class SearchPanelPadDelegate: NSObject, FloatingPanelControllerDelegate, UIGestureRecognizerDelegate {
|
||||
unowned let owner: MainViewController
|
||||
|
||||
init(owner: MainViewController) {
|
||||
self.owner = owner
|
||||
}
|
||||
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
if newCollection.horizontalSizeClass == .compact {
|
||||
fpc.surfaceView.containerMargins = .zero
|
||||
return FloatingPanelBottomLayout()
|
||||
}
|
||||
fpc.surfaceView.containerMargins = UIEdgeInsets(top: .leastNonzeroMagnitude, // For top left/right rounding corners
|
||||
left: 16,
|
||||
bottom: 0.0,
|
||||
right: 0.0)
|
||||
return SearchPanelPadLayout()
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
|
||||
if vc.state == .full {
|
||||
owner.searchVC.searchBar.showsCancelButton = false
|
||||
owner.searchVC.searchBar.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelWillEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetState: UnsafeMutablePointer<FloatingPanelState>) {
|
||||
if targetState.pointee != .full {
|
||||
owner.searchVC.hideHeader(animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SearchPanelPadLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .top
|
||||
let initialState: FloatingPanelState = .tip
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 80.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 200.0, edge: .top, referenceGuide: .superview),
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 60.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
return [
|
||||
surfaceView.leftAnchor.constraint(equalTo: view.leftAnchor),
|
||||
surfaceView.widthAnchor.constraint(equalToConstant: 375),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class SearchPaneliPadBehavior: FloatingPanelBehavior {
|
||||
var springDecelerationRate: CGFloat {
|
||||
return UIScrollView.DecelerationRate.fast.rawValue - 0.003
|
||||
}
|
||||
var springResponseTime: CGFloat {
|
||||
return 0.3
|
||||
}
|
||||
var momentumProjectionRate: CGFloat {
|
||||
return UIScrollView.DecelerationRate.fast.rawValue
|
||||
}
|
||||
func shouldProjectMomentum(_ fpc: FloatingPanelController, to proposedState: FloatingPanelState) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class DetailPanelPadDelegate: NSObject, FloatingPanelControllerDelegate, UIGestureRecognizerDelegate {
|
||||
unowned let owner: MainViewController
|
||||
|
||||
init(owner: MainViewController) {
|
||||
self.owner = owner
|
||||
}
|
||||
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
if newCollection.horizontalSizeClass == .compact {
|
||||
fpc.surfaceView.containerMargins = .zero
|
||||
return FloatingPanelBottomLayout()
|
||||
}
|
||||
if let item = owner.detailVC.item, item.title.contains("Right") {
|
||||
fpc.surfaceView.containerMargins = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: .leastNonzeroMagnitude)
|
||||
return DetailPanelPadRightLayout()
|
||||
}
|
||||
fpc.surfaceView.containerMargins = UIEdgeInsets(top: 0.0, left: .leastNonzeroMagnitude, bottom: 0.0, right: 0.0)
|
||||
return DetailPanelPadLeftLayout()
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class DetailPanelPadLeftLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .left
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 375, edge: .left, referenceGuide: .superview)
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
class DetailPanelPadRightLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .right
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 375, edge: .right, referenceGuide: .superview)
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MKMapViewDelegate
|
||||
|
||||
extension MainViewController: MKMapViewDelegate {
|
||||
func setUpMapView() {
|
||||
let center = CLLocationCoordinate2D(latitude: 37.623198015869235,
|
||||
longitude: -122.43066818432008)
|
||||
let span = MKCoordinateSpan(latitudeDelta: 0.4425100023575723,
|
||||
longitudeDelta: 0.28543697435880233)
|
||||
let region = MKCoordinateRegion(center: center, span: span)
|
||||
mapView.region = region
|
||||
mapView.showsCompass = true
|
||||
mapView.showsUserLocation = true
|
||||
mapView.delegate = self
|
||||
}
|
||||
|
||||
func tearDownMapView() {
|
||||
// Prevent a crash
|
||||
mapView.delegate = nil
|
||||
mapView = nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
extension MainViewController: UITableViewDelegate {
|
||||
func setUpSearchView() {
|
||||
searchVC.loadViewIfNeeded()
|
||||
searchVC.tableView.delegate = self
|
||||
searchVC.searchBar.placeholder = "Search for a place or address"
|
||||
let isPad = (traitCollection.userInterfaceIdiom == .pad)
|
||||
searchVC.items = [
|
||||
.init(mark: "mark", title: "Marked Location" + (isPad ? " (Left panel)" : ""), subtitle: "Golden Gate Bridge, San Francisco"),
|
||||
.init(mark: "mark", title: "Marked Location" + (isPad ? " (Right panel)" : ""), subtitle: "San Francisco Museum of Modern Art"),
|
||||
]
|
||||
searchVC.items.append(contentsOf: (0...98).map {
|
||||
.init(mark: "like", title: "Favorites", subtitle: "\($0) Places")
|
||||
})
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
deactivate(searchBar: searchVC.searchBar)
|
||||
|
||||
// Show a detail panel
|
||||
switch indexPath.row {
|
||||
case 0:
|
||||
detailVC.item = searchVC.items[safe: 0]
|
||||
|
||||
// Show detail vc in the left positioned panel
|
||||
switch traitCollection.userInterfaceIdiom {
|
||||
case .pad:
|
||||
detailFpc.layout = DetailPanelPadLeftLayout()
|
||||
detailFpc.surfaceView.containerMargins = UIEdgeInsets(top: 0.0, left: 16.0, bottom: 0.0, right: 0.0)
|
||||
default:
|
||||
detailFpc.layout = DetailPanelPhoneLayout()
|
||||
detailFpc.surfaceView.containerMargins = .zero
|
||||
}
|
||||
detailFpc.addPanel(toParent: self, animated: true)
|
||||
case 1:
|
||||
detailVC.item = searchVC.items[safe: 1]
|
||||
|
||||
// Show detail vc in the right positioned panel
|
||||
switch traitCollection.userInterfaceIdiom {
|
||||
case .pad:
|
||||
detailFpc.layout = DetailPanelPadRightLayout()
|
||||
detailFpc.surfaceView.containerMargins = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 16.0)
|
||||
default:
|
||||
detailFpc.layout = DetailPanelPhoneLayout()
|
||||
detailFpc.surfaceView.containerMargins = .zero
|
||||
}
|
||||
detailFpc.addPanel(toParent: self, animated: true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Models
|
||||
|
||||
struct LocationItem {
|
||||
let mark: String
|
||||
let title: String
|
||||
let subtitle: String
|
||||
|
||||
init(mark: String, title: String, subtitle: String) {
|
||||
self.mark = mark
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
class SearchViewController: UIViewController, UITableViewDataSource {
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
@IBOutlet weak var searchBar: UISearchBar!
|
||||
@IBOutlet weak var visualEffectView: UIVisualEffectView!
|
||||
|
||||
var items: [LocationItem] = []
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.dataSource = self
|
||||
searchBar.setSearchText(fontSize: 15.0)
|
||||
|
||||
hideHeader(animated: false)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return items.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||
if let cell = cell as? SearchCell, let item = items[safe: indexPath.row] {
|
||||
cell.iconImageView.image = UIImage(named: item.mark)
|
||||
cell.titleLabel.text = item.title
|
||||
cell.subTitleLabel.text = item.subtitle
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
func showHeader(animated: Bool) {
|
||||
changeHeader(height: 116.0, animated: animated)
|
||||
}
|
||||
|
||||
func hideHeader(animated: Bool) {
|
||||
changeHeader(height: 0.0, animated: animated)
|
||||
}
|
||||
|
||||
private func changeHeader(height: CGFloat, animated: Bool) {
|
||||
guard let headerView = tableView.tableHeaderView, headerView.bounds.height != height else { return }
|
||||
if animated == false {
|
||||
updateHeader(height: height)
|
||||
return
|
||||
}
|
||||
tableView.beginUpdates()
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.updateHeader(height: height)
|
||||
}
|
||||
tableView.endUpdates()
|
||||
}
|
||||
|
||||
private func updateHeader(height: CGFloat) {
|
||||
guard let headerView = tableView.tableHeaderView else { return }
|
||||
var frame = headerView.frame
|
||||
frame.size.height = height
|
||||
self.tableView.tableHeaderView?.frame = frame
|
||||
}
|
||||
}
|
||||
|
||||
class SearchCell: UITableViewCell {
|
||||
@IBOutlet weak var iconImageView: UIImageView!
|
||||
@IBOutlet weak var titleLabel: UILabel!
|
||||
@IBOutlet weak var subTitleLabel: UILabel!
|
||||
}
|
||||
|
||||
class SearchHeaderView: UIView {
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.clipsToBounds = true
|
||||
}
|
||||
}
|
||||
|
||||
extension UISearchBar {
|
||||
func setSearchText(fontSize: CGFloat) {
|
||||
if #available(iOS 13, *) {
|
||||
let font = searchTextField.font
|
||||
searchTextField.font = font?.withSize(fontSize)
|
||||
} else {
|
||||
let textField = value(forKey: "_searchField") as! UITextField
|
||||
textField.font = textField.font?.withSize(fontSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
extension Collection {
|
||||
subscript (safe index: Index) -> Element? {
|
||||
return indices.contains(index) ? self[index] : nil
|
||||
}
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
var isLandscape: Bool {
|
||||
if #available(iOS 13.0, *) {
|
||||
return view.window?.windowScene?.interfaceOrientation.isLandscape ?? false
|
||||
} else {
|
||||
return UIApplication.shared.statusBarOrientation.isLandscape
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
//
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MapKit
|
||||
import FloatingPanel
|
||||
|
||||
class ViewController: UIViewController, MKMapViewDelegate, UISearchBarDelegate, FloatingPanelControllerDelegate {
|
||||
var fpc: FloatingPanelController!
|
||||
var searchVC: SearchPanelViewController!
|
||||
|
||||
@IBOutlet weak var mapView: MKMapView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
// Initialize FloatingPanelController
|
||||
fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
|
||||
// Initialize FloatingPanelController and add the view
|
||||
fpc.surfaceView.backgroundColor = .clear
|
||||
fpc.surfaceView.cornerRadius = 9.0
|
||||
fpc.surfaceView.shadowHidden = false
|
||||
|
||||
searchVC = storyboard?.instantiateViewController(withIdentifier: "SearchPanel") as? SearchPanelViewController
|
||||
|
||||
// Add a content view controller
|
||||
fpc.show(searchVC, sender: self)
|
||||
fpc.track(scrollView: searchVC.tableView)
|
||||
|
||||
setupMapView()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
// Add FloatingPanel to a view with animation.
|
||||
fpc.add(toParent: self, animated: true)
|
||||
|
||||
// Must be here
|
||||
searchVC.searchBar.delegate = self
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
teardownMapView()
|
||||
}
|
||||
|
||||
func setupMapView() {
|
||||
let center = CLLocationCoordinate2D(latitude: 37.623198015869235,
|
||||
longitude: -122.43066818432008)
|
||||
let span = MKCoordinateSpan(latitudeDelta: 0.4425100023575723,
|
||||
longitudeDelta: 0.28543697435880233)
|
||||
let region = MKCoordinateRegion(center: center, span: span)
|
||||
mapView.region = region
|
||||
mapView.showsCompass = true
|
||||
mapView.showsUserLocation = true
|
||||
mapView.delegate = self
|
||||
}
|
||||
|
||||
func teardownMapView() {
|
||||
// Prevent a crash
|
||||
mapView.delegate = nil
|
||||
mapView = nil
|
||||
}
|
||||
|
||||
// MARK: UISearchBarDelegate
|
||||
|
||||
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
|
||||
searchBar.resignFirstResponder()
|
||||
searchBar.showsCancelButton = false
|
||||
searchVC.hideHeader()
|
||||
fpc.move(to: .half, animated: true)
|
||||
}
|
||||
|
||||
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
searchBar.showsCancelButton = true
|
||||
searchVC.showHeader()
|
||||
searchVC.tableView.alpha = 1.0
|
||||
fpc.move(to: .full, animated: true)
|
||||
}
|
||||
|
||||
// MARK: FloatingPanelControllerDelegate
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? {
|
||||
switch traitCollection.verticalSizeClass {
|
||||
case .compact:
|
||||
fpc.surfaceView.borderWidth = 1.0 / traitCollection.displayScale
|
||||
fpc.surfaceView.borderColor = UIColor.black.withAlphaComponent(0.2)
|
||||
default:
|
||||
fpc.surfaceView.borderWidth = 0.0
|
||||
fpc.surfaceView.borderColor = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func floatingPanelDidMove(_ vc: FloatingPanelController) {
|
||||
let y = vc.surfaceView.frame.origin.y
|
||||
let tipY = vc.originYOfSurface(for: .tip)
|
||||
if y > tipY - 44.0 {
|
||||
let progress = max(0.0, min((tipY - y) / 44.0, 1.0))
|
||||
self.searchVC.tableView.alpha = progress
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
|
||||
if vc.position == .full {
|
||||
searchVC.searchBar.showsCancelButton = false
|
||||
searchVC.searchBar.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition) {
|
||||
if targetPosition != .full {
|
||||
searchVC.hideHeader()
|
||||
}
|
||||
|
||||
UIView.animate(withDuration: 0.25,
|
||||
delay: 0.0,
|
||||
options: .allowUserInteraction,
|
||||
animations: {
|
||||
if targetPosition == .tip {
|
||||
self.searchVC.tableView.alpha = 0.0
|
||||
} else {
|
||||
self.searchVC.tableView.alpha = 1.0
|
||||
}
|
||||
}, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
class SearchPanelViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
@IBOutlet weak var searchBar: UISearchBar!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.dataSource = self
|
||||
tableView.delegate = self
|
||||
searchBar.placeholder = "Search for a place or address"
|
||||
let textField = searchBar.value(forKey: "_searchField") as! UITextField
|
||||
textField.font = UIFont(name: textField.font!.fontName, size: 15.0)
|
||||
|
||||
hideHeader()
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||
if let cell = cell as? SearchCell {
|
||||
switch indexPath.row {
|
||||
case 0:
|
||||
cell.iconImageView.image = UIImage(named: "mark")
|
||||
cell.titleLabel.text = "Marked Location"
|
||||
cell.subTitleLabel.text = "Golden Gate Bridge, San Francisco"
|
||||
case 1:
|
||||
cell.iconImageView.image = UIImage(named: "like")
|
||||
cell.titleLabel.text = "Favorites"
|
||||
cell.subTitleLabel.text = "0 Places"
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
}
|
||||
|
||||
func showHeader() {
|
||||
changeHeader(height: 116.0)
|
||||
}
|
||||
|
||||
func hideHeader() {
|
||||
changeHeader(height: 0.0)
|
||||
}
|
||||
|
||||
func changeHeader(height: CGFloat) {
|
||||
tableView.beginUpdates()
|
||||
if let headerView = tableView.tableHeaderView {
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
var frame = headerView.frame
|
||||
frame.size.height = height
|
||||
self.tableView.tableHeaderView?.frame = frame
|
||||
}
|
||||
}
|
||||
tableView.endUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
class SearchCell: UITableViewCell {
|
||||
@IBOutlet weak var iconImageView: UIImageView!
|
||||
@IBOutlet weak var titleLabel: UILabel!
|
||||
@IBOutlet weak var subTitleLabel: UILabel!
|
||||
}
|
||||
|
||||
class SearchHeaderView: UIView {
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.clipsToBounds = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5442E22425FC51AF00A26F43 /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E22325FC51AF00A26F43 /* ImageViewController.swift */; };
|
||||
5442E22825FC51E200A26F43 /* MultiPanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E22725FC51E200A26F43 /* MultiPanelController.swift */; };
|
||||
5442E22C25FC521F00A26F43 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E22B25FC521F00A26F43 /* SettingsViewController.swift */; };
|
||||
5442E23025FC525200A26F43 /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E22F25FC525200A26F43 /* TabBarViewController.swift */; };
|
||||
5442E23425FC528400A26F43 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E23325FC528400A26F43 /* DetailViewController.swift */; };
|
||||
5442E23A25FC52CD00A26F43 /* ModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E23925FC52CD00A26F43 /* ModalViewController.swift */; };
|
||||
5442E24025FC533800A26F43 /* DebugTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E23F25FC533800A26F43 /* DebugTableViewController.swift */; };
|
||||
5442E24425FC538200A26F43 /* InspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E24325FC538200A26F43 /* InspectorViewController.swift */; };
|
||||
5442E24A25FC53C100A26F43 /* DebugTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E24925FC53C100A26F43 /* DebugTextViewController.swift */; };
|
||||
5442E25225FC541700A26F43 /* NestedScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E25125FC541700A26F43 /* NestedScrollViewController.swift */; };
|
||||
54496C59263A7E5A0031E0C8 /* UseCaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54496C58263A7E5A0031E0C8 /* UseCaseController.swift */; };
|
||||
544BC56826CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 544BC56726CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift */; };
|
||||
545DB9EE21511E6300CA77B8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9ED21511E6300CA77B8 /* AppDelegate.swift */; };
|
||||
545DB9F021511E6300CA77B8 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9EF21511E6300CA77B8 /* MainViewController.swift */; };
|
||||
545DB9F321511E6300CA77B8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F121511E6300CA77B8 /* Main.storyboard */; };
|
||||
545DB9F521511E6400CA77B8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F421511E6400CA77B8 /* Assets.xcassets */; };
|
||||
545DB9F821511E6400CA77B8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F621511E6400CA77B8 /* LaunchScreen.storyboard */; };
|
||||
546341A125C6415100CA0596 /* UseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 546341A025C6415100CA0596 /* UseCase.swift */; };
|
||||
546341AC25C6426500CA0596 /* CustomState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 546341AB25C6426500CA0596 /* CustomState.swift */; };
|
||||
549D23CB233C7779008EF4D7 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CA233C7779008EF4D7 /* FloatingPanel.framework */; };
|
||||
549D23CC233C7779008EF4D7 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CA233C7779008EF4D7 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
54B51116216AFE5F0033A6F3 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B51115216AFE5F0033A6F3 /* Extensions.swift */; };
|
||||
54CDC5D8215BBE23007D205C /* SupplementaryViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */; };
|
||||
54E58CB72BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E58CB62BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift */; };
|
||||
54EAD35B263A75EB006A36EA /* PanelLayouts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EAD35A263A75EB006A36EA /* PanelLayouts.swift */; };
|
||||
54EAD365263A765F006A36EA /* PagePanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EAD364263A765F006A36EA /* PagePanelController.swift */; };
|
||||
54F185822BF4AD0000916F57 /* DebugListCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54F185812BF4AD0000916F57 /* DebugListCollectionViewController.swift */; };
|
||||
54F185842BF4B82E00916F57 /* UnavailableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54F185832BF4B82E00916F57 /* UnavailableViewController.swift */; };
|
||||
5D82A6AD28D1843C006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6AC28D18438006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
549D23CD233C7779008EF4D7 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
549D23CC233C7779008EF4D7 /* FloatingPanel.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5442E22325FC51AF00A26F43 /* ImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewController.swift; sourceTree = "<group>"; };
|
||||
5442E22725FC51E200A26F43 /* MultiPanelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiPanelController.swift; sourceTree = "<group>"; };
|
||||
5442E22B25FC521F00A26F43 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
|
||||
5442E22F25FC525200A26F43 /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = "<group>"; };
|
||||
5442E23325FC528400A26F43 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
|
||||
5442E23925FC52CD00A26F43 /* ModalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalViewController.swift; sourceTree = "<group>"; };
|
||||
5442E23F25FC533800A26F43 /* DebugTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugTableViewController.swift; sourceTree = "<group>"; };
|
||||
5442E24325FC538200A26F43 /* InspectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorViewController.swift; sourceTree = "<group>"; };
|
||||
5442E24925FC53C100A26F43 /* DebugTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugTextViewController.swift; sourceTree = "<group>"; };
|
||||
5442E25125FC541700A26F43 /* NestedScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedScrollViewController.swift; sourceTree = "<group>"; };
|
||||
54496C58263A7E5A0031E0C8 /* UseCaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseCaseController.swift; sourceTree = "<group>"; };
|
||||
544BC56726CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewControllerForAdaptiveLayout.swift; sourceTree = "<group>"; };
|
||||
545DB9EA21511E6300CA77B8 /* Samples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Samples.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DB9ED21511E6300CA77B8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
545DB9EF21511E6300CA77B8 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
545DB9F221511E6300CA77B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
545DB9F421511E6400CA77B8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
545DB9F721511E6400CA77B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
545DB9F921511E6400CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
546341A025C6415100CA0596 /* UseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseCase.swift; sourceTree = "<group>"; };
|
||||
546341AB25C6426500CA0596 /* CustomState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomState.swift; sourceTree = "<group>"; };
|
||||
549D23CA233C7779008EF4D7 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
54B51115216AFE5F0033A6F3 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
|
||||
54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupplementaryViews.swift; sourceTree = "<group>"; };
|
||||
54E58CB62BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewControllerForAdaptiveLayout.swift; sourceTree = "<group>"; };
|
||||
54EAD35A263A75EB006A36EA /* PanelLayouts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanelLayouts.swift; sourceTree = "<group>"; };
|
||||
54EAD364263A765F006A36EA /* PagePanelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagePanelController.swift; sourceTree = "<group>"; };
|
||||
54F185812BF4AD0000916F57 /* DebugListCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugListCollectionViewController.swift; sourceTree = "<group>"; };
|
||||
54F185832BF4B82E00916F57 /* UnavailableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnavailableViewController.swift; sourceTree = "<group>"; };
|
||||
5D82A6AC28D18438006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
545DB9E721511E6300CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D82A6AD28D1843C006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
549D23CB233C7779008EF4D7 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
5442E22225FC519700A26F43 /* ContentViewControllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54E58CB52BF8A88600408EA9 /* AdaptiveLayout */,
|
||||
5442E23F25FC533800A26F43 /* DebugTableViewController.swift */,
|
||||
5442E24925FC53C100A26F43 /* DebugTextViewController.swift */,
|
||||
54F185812BF4AD0000916F57 /* DebugListCollectionViewController.swift */,
|
||||
5442E23325FC528400A26F43 /* DetailViewController.swift */,
|
||||
5442E24325FC538200A26F43 /* InspectorViewController.swift */,
|
||||
5442E25125FC541700A26F43 /* NestedScrollViewController.swift */,
|
||||
5442E23925FC52CD00A26F43 /* ModalViewController.swift */,
|
||||
5442E22725FC51E200A26F43 /* MultiPanelController.swift */,
|
||||
5442E22B25FC521F00A26F43 /* SettingsViewController.swift */,
|
||||
5442E22F25FC525200A26F43 /* TabBarViewController.swift */,
|
||||
54F185832BF4B82E00916F57 /* UnavailableViewController.swift */,
|
||||
);
|
||||
path = ContentViewControllers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9E121511E6300CA77B8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
549D23CA233C7779008EF4D7 /* FloatingPanel.framework */,
|
||||
545DB9EC21511E6300CA77B8 /* Sources */,
|
||||
545DB9EB21511E6300CA77B8 /* Products */,
|
||||
5D82A6AB28D18438006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9EB21511E6300CA77B8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9EA21511E6300CA77B8 /* Samples.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9EC21511E6300CA77B8 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9F421511E6400CA77B8 /* Assets.xcassets */,
|
||||
545DB9F621511E6400CA77B8 /* LaunchScreen.storyboard */,
|
||||
545DB9F121511E6300CA77B8 /* Main.storyboard */,
|
||||
545DB9ED21511E6300CA77B8 /* AppDelegate.swift */,
|
||||
545DB9EF21511E6300CA77B8 /* MainViewController.swift */,
|
||||
546341AA25C6421000CA0596 /* UseCases */,
|
||||
5442E22225FC519700A26F43 /* ContentViewControllers */,
|
||||
54EAD35A263A75EB006A36EA /* PanelLayouts.swift */,
|
||||
546341AB25C6426500CA0596 /* CustomState.swift */,
|
||||
54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */,
|
||||
54B51115216AFE5F0033A6F3 /* Extensions.swift */,
|
||||
545DB9F921511E6400CA77B8 /* Info.plist */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
546341AA25C6421000CA0596 /* UseCases */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
546341A025C6415100CA0596 /* UseCase.swift */,
|
||||
54496C58263A7E5A0031E0C8 /* UseCaseController.swift */,
|
||||
54EAD364263A765F006A36EA /* PagePanelController.swift */,
|
||||
);
|
||||
path = UseCases;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
54E58CB52BF8A88600408EA9 /* AdaptiveLayout */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5442E22325FC51AF00A26F43 /* ImageViewController.swift */,
|
||||
544BC56726CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift */,
|
||||
54E58CB62BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift */,
|
||||
);
|
||||
path = AdaptiveLayout;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6AB28D18438006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6AC28D18438006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
545DB9E921511E6300CA77B8 /* Samples */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DBA1221511E6400CA77B8 /* Build configuration list for PBXNativeTarget "Samples" */;
|
||||
buildPhases = (
|
||||
545DB9E621511E6300CA77B8 /* Sources */,
|
||||
545DB9E721511E6300CA77B8 /* Frameworks */,
|
||||
545DB9E821511E6300CA77B8 /* Resources */,
|
||||
549D23CD233C7779008EF4D7 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Samples;
|
||||
productName = FloatingModalSample;
|
||||
productReference = 545DB9EA21511E6300CA77B8 /* Samples.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
545DB9E221511E6300CA77B8 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1000;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = scenee;
|
||||
TargetAttributes = {
|
||||
545DB9E921511E6300CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 545DB9E521511E6300CA77B8 /* Build configuration list for PBXProject "Samples" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 545DB9E121511E6300CA77B8;
|
||||
productRefGroup = 545DB9EB21511E6300CA77B8 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
545DB9E921511E6300CA77B8 /* Samples */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
545DB9E821511E6300CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DB9F821511E6400CA77B8 /* LaunchScreen.storyboard in Resources */,
|
||||
545DB9F521511E6400CA77B8 /* Assets.xcassets in Resources */,
|
||||
545DB9F321511E6300CA77B8 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
545DB9E621511E6300CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5442E23425FC528400A26F43 /* DetailViewController.swift in Sources */,
|
||||
54E58CB72BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift in Sources */,
|
||||
54496C59263A7E5A0031E0C8 /* UseCaseController.swift in Sources */,
|
||||
54CDC5D8215BBE23007D205C /* SupplementaryViews.swift in Sources */,
|
||||
54B51116216AFE5F0033A6F3 /* Extensions.swift in Sources */,
|
||||
544BC56826CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift in Sources */,
|
||||
5442E24A25FC53C100A26F43 /* DebugTextViewController.swift in Sources */,
|
||||
546341AC25C6426500CA0596 /* CustomState.swift in Sources */,
|
||||
5442E23A25FC52CD00A26F43 /* ModalViewController.swift in Sources */,
|
||||
5442E22425FC51AF00A26F43 /* ImageViewController.swift in Sources */,
|
||||
5442E24025FC533800A26F43 /* DebugTableViewController.swift in Sources */,
|
||||
54F185822BF4AD0000916F57 /* DebugListCollectionViewController.swift in Sources */,
|
||||
5442E25225FC541700A26F43 /* NestedScrollViewController.swift in Sources */,
|
||||
5442E22825FC51E200A26F43 /* MultiPanelController.swift in Sources */,
|
||||
546341A125C6415100CA0596 /* UseCase.swift in Sources */,
|
||||
545DB9F021511E6300CA77B8 /* MainViewController.swift in Sources */,
|
||||
545DB9EE21511E6300CA77B8 /* AppDelegate.swift in Sources */,
|
||||
5442E23025FC525200A26F43 /* TabBarViewController.swift in Sources */,
|
||||
54EAD35B263A75EB006A36EA /* PanelLayouts.swift in Sources */,
|
||||
54EAD365263A765F006A36EA /* PagePanelController.swift in Sources */,
|
||||
5442E24425FC538200A26F43 /* InspectorViewController.swift in Sources */,
|
||||
5442E22C25FC521F00A26F43 /* SettingsViewController.swift in Sources */,
|
||||
54F185842BF4B82E00916F57 /* UnavailableViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
545DB9F121511E6300CA77B8 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
545DB9F221511E6300CA77B8 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9F621511E6400CA77B8 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
545DB9F721511E6400CA77B8 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
545DBA1021511E6400CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DBA1121511E6400CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DBA1321511E6400CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Samples;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DBA1421511E6400CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Samples;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
545DB9E521511E6300CA77B8 /* Build configuration list for PBXProject "Samples" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DBA1021511E6400CA77B8 /* Debug */,
|
||||
545DBA1121511E6400CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DBA1221511E6400CA77B8 /* Build configuration list for PBXNativeTarget "Samples" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DBA1321511E6400CA77B8 /* Debug */,
|
||||
545DBA1421511E6400CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 545DB9E221511E6300CA77B8 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545DB9E921511E6300CA77B8"
|
||||
BuildableName = "Samples.app"
|
||||
BlueprintName = "Samples"
|
||||
ReferencedContainer = "container:Samples.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545DB9E921511E6300CA77B8"
|
||||
BuildableName = "Samples.app"
|
||||
BlueprintName = "Samples"
|
||||
ReferencedContainer = "container:Samples.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545DB9E921511E6300CA77B8"
|
||||
BuildableName = "Samples.app"
|
||||
BlueprintName = "Samples"
|
||||
ReferencedContainer = "container:Samples.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545DB9E921511E6300CA77B8"
|
||||
BuildableName = "Samples.app"
|
||||
BlueprintName = "Samples"
|
||||
ReferencedContainer = "container:Samples.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "IMG_0003.jpg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,873 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="RoN-h0-uBD">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="Cjh-iX-VQw">
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="RootNavigationController" id="RoN-h0-uBD" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="hNW-5m-Omi">
|
||||
<rect key="frame" x="0.0" y="48" width="414" height="96"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="jF4-A0-Eq6" kind="relationship" relationship="rootViewController" id="W9V-or-flQ"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="lKu-or-aPl" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-705" y="27"/>
|
||||
</scene>
|
||||
<!--Samples-->
|
||||
<scene sceneID="35L-Gs-Vts">
|
||||
<objects>
|
||||
<viewController id="jF4-A0-Eq6" customClass="MainViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Smh-Bd-AAc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="7IS-PU-x0P">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="M0G-C8-hAO" style="IBUITableViewCellStyleDefault" id="ySY-oA-g81">
|
||||
<rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ySY-oA-g81" id="sXB-nH-2g2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="M0G-C8-hAO">
|
||||
<rect key="frame" x="20" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="39L-Nq-qfp"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="7IS-PU-x0P" firstAttribute="top" secondItem="Smh-Bd-AAc" secondAttribute="top" id="6yd-jv-ey3"/>
|
||||
<constraint firstItem="7IS-PU-x0P" firstAttribute="leading" secondItem="39L-Nq-qfp" secondAttribute="leading" id="Z6Y-Dc-cei"/>
|
||||
<constraint firstItem="7IS-PU-x0P" firstAttribute="bottom" secondItem="Smh-Bd-AAc" secondAttribute="bottom" id="fNW-DP-lhV"/>
|
||||
<constraint firstItem="7IS-PU-x0P" firstAttribute="trailing" secondItem="39L-Nq-qfp" secondAttribute="trailing" id="vfY-Rc-FOI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Samples" id="wCF-su-7up">
|
||||
<barButtonItem key="rightBarButtonItem" title="Settings" id="rbH-U3-XyA">
|
||||
<connections>
|
||||
<action selector="showDebugMenu:" destination="jF4-A0-Eq6" id="j02-db-ZM5"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="tableView" destination="7IS-PU-x0P" id="YFM-9W-eP4"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="eP2-DG-flv" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="57" y="27"/>
|
||||
</scene>
|
||||
<!--Settings View Controller-->
|
||||
<scene sceneID="Bd0-D2-agO">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="SettingsViewController" id="C1X-9Z-TyQ" customClass="SettingsViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="af9-Zr-Ppc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="197.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="n93-ZL-fmC">
|
||||
<rect key="frame" x="32" y="16" width="311" height="149.5"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="DCi-Iv-o6d">
|
||||
<rect key="frame" x="0.0" y="0.0" width="311" height="53"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version: 1.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WmC-Tq-NDN">
|
||||
<rect key="frame" x="118.5" y="0.0" width="74.5" height="17.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UINavigationBar" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ulg-gS-ah0">
|
||||
<rect key="frame" x="78.5" y="25.5" width="154.5" height="27.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle2"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="J8j-7w-yCZ">
|
||||
<rect key="frame" x="0.0" y="69" width="311" height="80.5"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="uEf-g4-CeU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="311" height="32"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Large Titles" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ogl-S5-4tJ">
|
||||
<rect key="frame" x="0.0" y="5.5" width="254" height="20.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="js8-Qv-lUC">
|
||||
<rect key="frame" x="262" y="0.5" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="toggleLargeTitle:" destination="C1X-9Z-TyQ" eventType="valueChanged" id="CxM-wn-r09"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="ZtZ-Dz-4cC">
|
||||
<rect key="frame" x="0.0" y="48" width="311" height="32.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Translucent" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z5i-rm-QgL">
|
||||
<rect key="frame" x="0.0" y="6" width="254" height="20.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="s6b-j9-8Kw">
|
||||
<rect key="frame" x="262" y="0.5" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="toggleTranslucent:" destination="C1X-9Z-TyQ" eventType="valueChanged" id="w7r-AV-RqX"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="0hr-ty-yWm"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="n93-ZL-fmC" secondAttribute="bottom" constant="32" id="2Ey-ou-E1M"/>
|
||||
<constraint firstAttribute="trailing" secondItem="n93-ZL-fmC" secondAttribute="trailing" constant="32" id="DdZ-eB-F5s"/>
|
||||
<constraint firstItem="n93-ZL-fmC" firstAttribute="leading" secondItem="af9-Zr-Ppc" secondAttribute="leading" constant="32" id="TyK-GP-Ari"/>
|
||||
<constraint firstItem="n93-ZL-fmC" firstAttribute="top" secondItem="af9-Zr-Ppc" secondAttribute="topMargin" constant="16" id="mbC-6H-z9M"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="197.33000000000001"/>
|
||||
<connections>
|
||||
<outlet property="largeTitlesSwitch" destination="js8-Qv-lUC" id="szl-pU-uRE"/>
|
||||
<outlet property="translucentSwitch" destination="s6b-j9-8Kw" id="8yK-Du-jkM"/>
|
||||
<outlet property="versionLabel" destination="WmC-Tq-NDN" id="Woh-kK-U0m"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="M9h-4V-3M0" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="708" y="-200"/>
|
||||
</scene>
|
||||
<!--Layout 2-->
|
||||
<scene sceneID="lRc-OZ-sL4">
|
||||
<objects>
|
||||
<viewController id="RpE-lI-27a" customClass="TabBarContentViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="JER-jz-KSq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IvG-yp-yzI">
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="RpE-lI-27a" eventType="touchUpInside" id="hj3-Xv-6Gq"/>
|
||||
<action selector="closeWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="rg4-OH-Ojn"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="954-Dk-zvc"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="IvG-yp-yzI" firstAttribute="top" secondItem="954-Dk-zvc" secondAttribute="top" id="18k-sV-PgT"/>
|
||||
<constraint firstItem="954-Dk-zvc" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="IvG-yp-yzI" secondAttribute="trailing" id="mpr-u5-MZu"/>
|
||||
<constraint firstItem="IvG-yp-yzI" firstAttribute="leading" secondItem="954-Dk-zvc" secondAttribute="leading" constant="20" id="pYt-jE-CTF"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" tag="1" title="Layout 2" id="qb3-RB-B28"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="NhZ-u5-Beh" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-308" y="1546"/>
|
||||
</scene>
|
||||
<!--Layout 3-->
|
||||
<scene sceneID="r9h-Ql-gIv">
|
||||
<objects>
|
||||
<viewController id="pOk-Zm-vD9" customClass="TabBarContentViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="85d-ub-G8k">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NbG-e8-HdI">
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="pOk-Zm-vD9" eventType="touchUpInside" id="111-PD-Pop"/>
|
||||
<action selector="closeWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="1Rg-YG-TtU"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="0ao-SI-QZW"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="0ao-SI-QZW" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="NbG-e8-HdI" secondAttribute="trailing" id="K9F-6x-KWn"/>
|
||||
<constraint firstItem="NbG-e8-HdI" firstAttribute="top" secondItem="0ao-SI-QZW" secondAttribute="top" id="nsE-so-rTl"/>
|
||||
<constraint firstItem="NbG-e8-HdI" firstAttribute="leading" secondItem="0ao-SI-QZW" secondAttribute="leading" constant="20" id="sF4-Dm-aoY"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" tag="2" title="Layout 3" id="RJD-TF-Sdh"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Oe3-FT-q1C" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="332" y="1546"/>
|
||||
</scene>
|
||||
<!--Layout 1-->
|
||||
<scene sceneID="m6X-j6-yBM">
|
||||
<objects>
|
||||
<viewController id="lto-Zc-Vtp" customClass="TabBarContentViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="ji9-Ez-N7i">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eFN-tN-4Ct">
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="YL4-GP-ZEZ"/>
|
||||
<action selector="closeWithSender:" destination="lto-Zc-Vtp" eventType="touchUpInside" id="llo-9x-fQv"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="5Ns-4l-Ufg"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="eFN-tN-4Ct" firstAttribute="leading" secondItem="5Ns-4l-Ufg" secondAttribute="leading" constant="20" id="5BT-yZ-EKe"/>
|
||||
<constraint firstItem="5Ns-4l-Ufg" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="eFN-tN-4Ct" secondAttribute="trailing" id="OzZ-Dz-RNF"/>
|
||||
<constraint firstItem="eFN-tN-4Ct" firstAttribute="top" secondItem="5Ns-4l-Ufg" secondAttribute="top" id="hUV-3a-XkY"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" title="Layout 1" id="HEV-kf-jxH"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="bkL-bc-hZC" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-962" y="1546"/>
|
||||
</scene>
|
||||
<!--Intrinsic View Controller-->
|
||||
<scene sceneID="wtJ-qZ-aCl">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="IntrinsicViewController" title="Intrinsic View Controller" id="aK0-kv-mTu" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="eLM-xc-d9e">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="1000" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" verticalCompressionResistancePriority="1000" text="Change this text" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ge4-RW-Gmz">
|
||||
<rect key="frame" x="125.5" y="24" width="124" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="ouu-g9-OiX"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="ge4-RW-Gmz" firstAttribute="top" secondItem="eLM-xc-d9e" secondAttribute="top" constant="24" id="j0s-fd-MYj"/>
|
||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="ge4-RW-Gmz" secondAttribute="bottom" constant="24" id="tEn-PO-nVD"/>
|
||||
<constraint firstItem="ge4-RW-Gmz" firstAttribute="centerX" secondItem="eLM-xc-d9e" secondAttribute="centerX" id="vh3-l7-uY8"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="DfE-fL-zy5" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2753" y="734"/>
|
||||
</scene>
|
||||
<!--Image View Controller-->
|
||||
<scene sceneID="NAI-Rh-ZQ6">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ImageViewController" id="VWY-cF-RoY" customClass="ImageViewController" customModule="Samples" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="dAf-gD-ghB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Gs4-S6-Goh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="t7x-eG-MKh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
|
||||
<color key="backgroundColor" systemColor="systemOrangeColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="49" id="DmG-pt-gij"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" alwaysBounceHorizontal="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kRA-qy-GpJ">
|
||||
<rect key="frame" x="0.0" y="49" width="375" height="680"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="1000" verticalHuggingPriority="1000" image="IMG_0003" translatesAutoresizingMaskIntoConstraints="NO" id="rGf-jW-WNf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="750" height="501"/>
|
||||
<color key="backgroundColor" systemColor="systemPurpleColor"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0078431372550000003" green="0.72156862749999995" blue="0.45882352939999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="rGf-jW-WNf" secondAttribute="trailing" id="472-Be-cUl"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rGf-jW-WNf" secondAttribute="bottom" id="ncs-tN-3Wx"/>
|
||||
<constraint firstItem="rGf-jW-WNf" firstAttribute="leading" secondItem="kRA-qy-GpJ" secondAttribute="leading" id="rlv-5Y-utR"/>
|
||||
<constraint firstItem="rGf-jW-WNf" firstAttribute="top" secondItem="kRA-qy-GpJ" secondAttribute="top" id="zum-Zl-Wzz"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SEa-7Y-wa9">
|
||||
<rect key="frame" x="0.0" y="729" width="375" height="49"/>
|
||||
<color key="backgroundColor" systemColor="systemTealColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="49" id="3mS-zi-8BP"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="hCg-v5-nJs"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="Gs4-S6-Goh" secondAttribute="trailing" id="6z7-Md-pxr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Gs4-S6-Goh" secondAttribute="bottom" id="PcQ-bu-yT3"/>
|
||||
<constraint firstItem="Gs4-S6-Goh" firstAttribute="top" secondItem="dAf-gD-ghB" secondAttribute="top" id="zGx-Wd-hjz"/>
|
||||
<constraint firstItem="Gs4-S6-Goh" firstAttribute="leading" secondItem="dAf-gD-ghB" secondAttribute="leading" id="zxi-Ty-U7L"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="footerView" destination="SEa-7Y-wa9" id="Gzj-dP-YXl"/>
|
||||
<outlet property="headerView" destination="t7x-eG-MKh" id="njM-un-U8q"/>
|
||||
<outlet property="scrollView" destination="kRA-qy-GpJ" id="iWC-o4-APi"/>
|
||||
<outlet property="stackView" destination="Gs4-S6-Goh" id="f1D-bO-mjr"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="pnR-69-Ek4" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3388" y="734.48275862068965"/>
|
||||
</scene>
|
||||
<!--Tab Bar View Controller-->
|
||||
<scene sceneID="nQ5-PV-qFw">
|
||||
<objects>
|
||||
<tabBarController storyboardIdentifier="TabBarViewController" id="c7K-XJ-TlT" customClass="TabBarViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="BPL-Dp-5pJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tabBar>
|
||||
<connections>
|
||||
<segue destination="lto-Zc-Vtp" kind="relationship" relationship="viewControllers" id="6hP-AH-YiH"/>
|
||||
<segue destination="RpE-lI-27a" kind="relationship" relationship="viewControllers" id="g6X-Sq-uSW"/>
|
||||
<segue destination="pOk-Zm-vD9" kind="relationship" relationship="viewControllers" id="OPp-iO-iDK"/>
|
||||
</connections>
|
||||
</tabBarController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Z9x-EI-p2b" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-706" y="749"/>
|
||||
</scene>
|
||||
<!--Modal View Controller-->
|
||||
<scene sceneID="C9P-Ns-Qrq">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ModalViewController" id="bYI-y3-Rzb" customClass="ModalViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="qwo-GK-p1U">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="768"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vut-mK-Y4t" customClass="SafeAreaView" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="768" width="375" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sbF-Az-7sy">
|
||||
<rect key="frame" x="20" y="0.0" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="MSC-ch-YJK"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="44" translatesAutoresizingMaskIntoConstraints="NO" id="9p4-06-y2T">
|
||||
<rect key="frame" x="134.5" y="88" width="106" height="326"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="i9x-x5-n1q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="80" height="30"/>
|
||||
<state key="normal" title="Move to full"/>
|
||||
<connections>
|
||||
<action selector="moveToFullWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="TDe-3J-gIR"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2u5-cH-RAN">
|
||||
<rect key="frame" x="0.0" y="74" width="85" height="30"/>
|
||||
<state key="normal" title="Move to half"/>
|
||||
<connections>
|
||||
<action selector="moveToHalfWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="12s-o7-Et5"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="M4A-iO-RIE">
|
||||
<rect key="frame" x="0.0" y="148" width="77" height="30"/>
|
||||
<state key="normal" title="Move to tip"/>
|
||||
<connections>
|
||||
<action selector="moveToTipWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="BmL-91-9ai"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="swr-XM-GzZ">
|
||||
<rect key="frame" x="0.0" y="222" width="106" height="30"/>
|
||||
<state key="normal" title="Move to hidden"/>
|
||||
<connections>
|
||||
<action selector="moveToHiddenWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="jfJ-0f-fdk"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="szf-HE-QTk">
|
||||
<rect key="frame" x="0.0" y="296" width="96" height="30"/>
|
||||
<state key="normal" title="Update layout"/>
|
||||
<connections>
|
||||
<action selector="updateLayout:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="Woz-a7-YMJ"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="kjr-TP-fcM"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="sbF-Az-7sy" firstAttribute="top" secondItem="kjr-TP-fcM" secondAttribute="top" id="3VR-hj-zeQ"/>
|
||||
<constraint firstItem="9p4-06-y2T" firstAttribute="top" secondItem="kjr-TP-fcM" secondAttribute="top" constant="88" id="41n-Fn-hi3"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vut-mK-Y4t" secondAttribute="bottom" id="6eq-Kt-heZ"/>
|
||||
<constraint firstItem="sbF-Az-7sy" firstAttribute="leading" secondItem="kjr-TP-fcM" secondAttribute="leading" constant="20" id="T2G-1L-PRs"/>
|
||||
<constraint firstItem="vut-mK-Y4t" firstAttribute="leading" secondItem="kjr-TP-fcM" secondAttribute="leading" id="gVC-jv-VJX"/>
|
||||
<constraint firstItem="vut-mK-Y4t" firstAttribute="trailing" secondItem="kjr-TP-fcM" secondAttribute="trailing" id="jkq-p2-lUm"/>
|
||||
<constraint firstItem="9p4-06-y2T" firstAttribute="centerX" secondItem="kjr-TP-fcM" secondAttribute="centerX" id="l8t-p3-ETf"/>
|
||||
<constraint firstItem="vut-mK-Y4t" firstAttribute="top" secondItem="kjr-TP-fcM" secondAttribute="bottom" id="rMy-JT-t4B"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="safeAreaView" destination="vut-mK-Y4t" id="r9P-XF-wLd"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="fbi-LZ-M4Y" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1375" y="734"/>
|
||||
</scene>
|
||||
<!--Nested Scroll View Controller-->
|
||||
<scene sceneID="TfC-A3-4R0">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="NestedScrollViewController" id="LAe-jm-k6f" customClass="NestedScrollViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="414-Wy-0t1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sBe-tN-uMi">
|
||||
<rect key="frame" x="0.0" y="32" width="375" height="746"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="lFR-Sp-Sj1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="968"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceHorizontal="YES" pagingEnabled="YES" showsVerticalScrollIndicator="NO" bouncesZoom="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xba-kG-VQ2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="242"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WRe-tD-KTb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1125" height="242"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WuE-iq-0GW">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="242"/>
|
||||
<color key="backgroundColor" red="1" green="0.57810515169999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w5Y-44-79g">
|
||||
<rect key="frame" x="375" y="0.0" width="375" height="242"/>
|
||||
<color key="backgroundColor" red="0.0078431372550000003" green="0.72156862749999995" blue="0.45882352939999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jQf-k3-eAa">
|
||||
<rect key="frame" x="750" y="0.0" width="375" height="242"/>
|
||||
<color key="backgroundColor" red="0.016804177310000001" green="0.19835099580000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="w5Y-44-79g" firstAttribute="width" secondItem="WuE-iq-0GW" secondAttribute="width" id="kHy-eU-guw"/>
|
||||
<constraint firstAttribute="height" constant="242" id="qzg-fI-j20"/>
|
||||
<constraint firstItem="jQf-k3-eAa" firstAttribute="width" secondItem="WuE-iq-0GW" secondAttribute="width" id="zDe-Uj-FO0"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="WRe-tD-KTb" firstAttribute="leading" secondItem="xba-kG-VQ2" secondAttribute="leading" id="7QG-dB-afb"/>
|
||||
<constraint firstAttribute="height" constant="242" id="Efw-D6-ksg"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WRe-tD-KTb" secondAttribute="trailing" id="ReM-cV-k0J"/>
|
||||
<constraint firstItem="WRe-tD-KTb" firstAttribute="top" secondItem="xba-kG-VQ2" secondAttribute="top" id="Xla-QL-qwm"/>
|
||||
<constraint firstItem="WuE-iq-0GW" firstAttribute="width" secondItem="xba-kG-VQ2" secondAttribute="width" id="qm0-cd-P69"/>
|
||||
<constraint firstAttribute="bottom" secondItem="WRe-tD-KTb" secondAttribute="bottom" id="uha-Eo-lsv"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="j8d-Tc-XQn">
|
||||
<rect key="frame" x="0.0" y="242" width="375" height="242"/>
|
||||
<color key="backgroundColor" red="0.0078431372550000003" green="0.72156862749999995" blue="0.45882352939999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="242" id="Kw8-aw-DIp"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bxy-HF-a7J">
|
||||
<rect key="frame" x="0.0" y="484" width="375" height="242"/>
|
||||
<color key="backgroundColor" red="1" green="0.2527923882" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="242" id="AIb-xl-srX"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZzA-fs-Va5">
|
||||
<rect key="frame" x="0.0" y="726" width="375" height="242"/>
|
||||
<color key="backgroundColor" red="0.016804177310000001" green="0.19835099580000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="242" id="TC1-jO-Wcz"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="lFR-Sp-Sj1" firstAttribute="width" secondItem="sBe-tN-uMi" secondAttribute="width" id="AtD-2C-97K"/>
|
||||
<constraint firstAttribute="trailing" secondItem="lFR-Sp-Sj1" secondAttribute="trailing" id="F7t-Kr-VGd"/>
|
||||
<constraint firstItem="lFR-Sp-Sj1" firstAttribute="leading" secondItem="sBe-tN-uMi" secondAttribute="leading" id="LzI-O9-5i0"/>
|
||||
<constraint firstItem="lFR-Sp-Sj1" firstAttribute="top" secondItem="sBe-tN-uMi" secondAttribute="top" id="VwX-Hz-e8V"/>
|
||||
<constraint firstAttribute="bottom" secondItem="lFR-Sp-Sj1" secondAttribute="bottom" id="hJt-0Z-dF3"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="ufS-Rf-F2F"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstItem="sBe-tN-uMi" firstAttribute="leading" secondItem="ufS-Rf-F2F" secondAttribute="leading" id="8Qd-my-knA"/>
|
||||
<constraint firstItem="sBe-tN-uMi" firstAttribute="top" secondItem="414-Wy-0t1" secondAttribute="top" constant="32" id="9Js-LU-lNr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="sBe-tN-uMi" secondAttribute="bottom" id="jzB-47-P7e"/>
|
||||
<constraint firstItem="ufS-Rf-F2F" firstAttribute="trailing" secondItem="sBe-tN-uMi" secondAttribute="trailing" id="nHG-wg-pLP"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="tOa-bf-zGz" appends="YES" id="zle-Sz-M3U"/>
|
||||
<outletCollection property="gestureRecognizers" destination="SCk-hG-weZ" appends="YES" id="OcK-FK-Lac"/>
|
||||
<outletCollection property="gestureRecognizers" destination="Fvp-Z6-eVc" appends="YES" id="Fds-J5-YCg"/>
|
||||
</connections>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="nestedScrollView" destination="xba-kG-VQ2" id="ddV-kf-37A"/>
|
||||
<outlet property="scrollView" destination="sBe-tN-uMi" id="h4S-Zl-cLO"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="QSd-gF-l5h" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="tOa-bf-zGz">
|
||||
<connections>
|
||||
<action selector="longPressed:" destination="LAe-jm-k6f" id="sE8-3l-Aos"/>
|
||||
</connections>
|
||||
</pongPressGestureRecognizer>
|
||||
<tapGestureRecognizer id="SCk-hG-weZ">
|
||||
<connections>
|
||||
<action selector="tapped:" destination="LAe-jm-k6f" id="0Cw-vR-zRP"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<swipeGestureRecognizer direction="right" id="Fvp-Z6-eVc">
|
||||
<connections>
|
||||
<action selector="swipped:" destination="LAe-jm-k6f" id="Hav-7p-Tg8"/>
|
||||
</connections>
|
||||
</swipeGestureRecognizer>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2097" y="734"/>
|
||||
</scene>
|
||||
<!--Detail View Controller-->
|
||||
<scene sceneID="b6k-zi-3wn">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="DetailViewController" id="YC8-ae-15L" customClass="DetailViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="g7l-kO-y7q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8yw-OC-Ubk">
|
||||
<rect key="frame" x="0.0" y="690" width="375" height="88"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="88" id="jwV-YU-tXG"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Kva-Z7-0qY" customClass="OnSafeAreaView" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="744"/>
|
||||
<color key="backgroundColor" red="0.0078431372550000003" green="0.72156862749999995" blue="0.45882352939999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="noi-1a-5bZ" customClass="CloseButton" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="319" y="48" width="44" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="0jg-5D-A1F"/>
|
||||
<constraint firstAttribute="width" constant="44" id="1Cq-PA-wgW"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="YC8-ae-15L" eventType="touchUpInside" id="Z2v-19-S5k"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillProportionally" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="qux-uG-4o2">
|
||||
<rect key="frame" x="8" y="56" width="148" height="31"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="fitToBounds" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7lq-d3-PKi">
|
||||
<rect key="frame" x="0.0" y="5.5" width="91" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0MA-lV-KjS">
|
||||
<rect key="frame" x="99" y="0.0" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="modeChanged:" destination="YC8-ae-15L" eventType="valueChanged" id="IQ8-u2-Rib"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="22" translatesAutoresizingMaskIntoConstraints="NO" id="tP3-oJ-4EB">
|
||||
<rect key="frame" x="130.5" y="88" width="114" height="134"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="c5r-jU-haj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="114" height="30"/>
|
||||
<state key="normal" title="Show"/>
|
||||
<connections>
|
||||
<action selector="buttonPressed:" destination="YC8-ae-15L" eventType="touchUpInside" id="Mi1-o6-TWt"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wmd-ab-Nz3">
|
||||
<rect key="frame" x="0.0" y="52" width="114" height="30"/>
|
||||
<state key="normal" title="Present Modallly"/>
|
||||
<connections>
|
||||
<action selector="buttonPressed:" destination="YC8-ae-15L" eventType="touchUpInside" id="tjH-Ev-kpx"/>
|
||||
<segue destination="bYI-y3-Rzb" kind="presentation" identifier="PresentModallySegue" id="3yq-HE-Tgn"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="01L-lp-oy6">
|
||||
<rect key="frame" x="0.0" y="104" width="114" height="30"/>
|
||||
<state key="normal" title="Update Layout"/>
|
||||
<connections>
|
||||
<action selector="buttonPressed:" destination="YC8-ae-15L" eventType="touchUpInside" id="zTb-sq-B6f"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="aOK-7l-cA6"/>
|
||||
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="top" secondItem="g7l-kO-y7q" secondAttribute="top" id="A4b-Le-m4I"/>
|
||||
<constraint firstItem="noi-1a-5bZ" firstAttribute="top" secondItem="aOK-7l-cA6" secondAttribute="top" priority="750" id="EQy-cr-F2Y"/>
|
||||
<constraint firstItem="tP3-oJ-4EB" firstAttribute="centerX" secondItem="aOK-7l-cA6" secondAttribute="centerX" id="EsD-Vf-dNZ"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="bottom" secondItem="g7l-kO-y7q" secondAttribute="bottom" priority="750" id="JOL-wC-w74"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="leading" secondItem="aOK-7l-cA6" secondAttribute="leading" id="RiJ-Hb-OOZ"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="trailing" secondItem="aOK-7l-cA6" secondAttribute="trailing" id="Sof-yL-mwK"/>
|
||||
<constraint firstItem="tP3-oJ-4EB" firstAttribute="top" secondItem="g7l-kO-y7q" secondAttribute="top" priority="750" constant="88" id="Zhb-Ss-epe"/>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="trailing" secondItem="aOK-7l-cA6" secondAttribute="trailing" id="kkp-Yo-FQW"/>
|
||||
<constraint firstItem="aOK-7l-cA6" firstAttribute="trailing" secondItem="noi-1a-5bZ" secondAttribute="trailing" constant="12" id="lv9-Nf-HNB"/>
|
||||
<constraint firstItem="qux-uG-4o2" firstAttribute="top" secondItem="aOK-7l-cA6" secondAttribute="top" constant="8" id="naa-cf-ZIc"/>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="leading" secondItem="aOK-7l-cA6" secondAttribute="leading" id="oVC-i1-TwS"/>
|
||||
<constraint firstItem="aOK-7l-cA6" firstAttribute="bottom" secondItem="Kva-Z7-0qY" secondAttribute="bottom" priority="750" id="rW2-mF-5DR"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="top" relation="greaterThanOrEqual" secondItem="tP3-oJ-4EB" secondAttribute="bottom" priority="750" constant="88" id="vKQ-h9-uKt"/>
|
||||
<constraint firstItem="qux-uG-4o2" firstAttribute="leading" secondItem="g7l-kO-y7q" secondAttribute="leading" constant="8" id="zXb-R9-bMO"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="6Ca-p8-7uF" appends="YES" id="xOy-f1-NZE"/>
|
||||
<outletCollection property="gestureRecognizers" destination="SPY-Vr-XDT" appends="YES" id="vgS-Am-jhQ"/>
|
||||
<outletCollection property="gestureRecognizers" destination="Jg4-it-qJ5" appends="YES" id="ONf-5y-phY"/>
|
||||
</connections>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="closeButton" destination="noi-1a-5bZ" id="eWQ-ha-8y7"/>
|
||||
<outlet property="intrinsicHeightConstraint" destination="vKQ-h9-uKt" id="QpA-WD-b17"/>
|
||||
<outlet property="modeChangeView" destination="qux-uG-4o2" id="1Nq-fE-dXw"/>
|
||||
<segue destination="bYI-y3-Rzb" kind="show" identifier="ShowSegue" id="r1P-2i-NDe"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Wqk-xl-O3I" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<tapGestureRecognizer id="6Ca-p8-7uF">
|
||||
<connections>
|
||||
<action selector="tapped:" destination="YC8-ae-15L" id="KFd-eT-RLn"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<swipeGestureRecognizer direction="right" id="SPY-Vr-XDT">
|
||||
<connections>
|
||||
<action selector="swipped:" destination="YC8-ae-15L" id="OFa-4C-8rI"/>
|
||||
</connections>
|
||||
</swipeGestureRecognizer>
|
||||
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="Jg4-it-qJ5">
|
||||
<connections>
|
||||
<action selector="longPressed:" destination="YC8-ae-15L" id="1G4-cf-RDE"/>
|
||||
</connections>
|
||||
</pongPressGestureRecognizer>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="653.60000000000002" y="733.74384236453204"/>
|
||||
</scene>
|
||||
<!--Debug Text View Controller-->
|
||||
<scene sceneID="Bkq-O7-q4A">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ConsoleViewController" id="tvD-nO-QUb" customClass="DebugTextViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="9YG-0j-Zzg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" bouncesZoom="NO" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rN1-HL-YHv">
|
||||
<rect key="frame" x="0.0" y="17" width="375" height="761"/>
|
||||
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<string key="text">The standard Lorem Ipsum passage, used since the 1500s
|
||||
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||
|
||||
Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
||||
|
||||
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
|
||||
|
||||
1914 translation by H. Rackham
|
||||
|
||||
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
|
||||
|
||||
Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
||||
|
||||
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."
|
||||
|
||||
1914 translation by H. Rackham
|
||||
|
||||
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."
|
||||
|
||||
The standard Lorem Ipsum passage, used since the 1500s
|
||||
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||
|
||||
Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
||||
|
||||
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
|
||||
|
||||
1914 translation by H. Rackham
|
||||
|
||||
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
|
||||
|
||||
Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
||||
|
||||
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."
|
||||
|
||||
1914 translation by H. Rackham
|
||||
|
||||
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</string>
|
||||
<fontDescription key="fontDescription" name="CourierNewPSMT" family="Courier New" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillProportionally" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="wUo-kb-NIn">
|
||||
<rect key="frame" x="159" y="16" width="200" height="31"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Expand top margin" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OC3-od-ldC">
|
||||
<rect key="frame" x="0.0" y="5.5" width="143" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="XFC-sq-pWj">
|
||||
<rect key="frame" x="151" y="0.0" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="toggleTopMargin:" destination="tvD-nO-QUb" eventType="valueChanged" id="XWo-eX-0Jn"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="5ET-zC-lCb"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="rN1-HL-YHv" firstAttribute="leading" secondItem="5ET-zC-lCb" secondAttribute="leading" id="7V3-KL-vXd"/>
|
||||
<constraint firstItem="5ET-zC-lCb" firstAttribute="trailing" secondItem="wUo-kb-NIn" secondAttribute="trailing" constant="16" id="CtG-H5-tAI"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rN1-HL-YHv" secondAttribute="bottom" id="efD-U5-Tet"/>
|
||||
<constraint firstItem="rN1-HL-YHv" firstAttribute="top" secondItem="9YG-0j-Zzg" secondAttribute="top" constant="17" id="fiO-LL-nSC"/>
|
||||
<constraint firstItem="rN1-HL-YHv" firstAttribute="trailing" secondItem="5ET-zC-lCb" secondAttribute="trailing" id="lfg-EE-euw"/>
|
||||
<constraint firstItem="wUo-kb-NIn" firstAttribute="top" secondItem="9YG-0j-Zzg" secondAttribute="top" constant="16" id="ogC-1W-upw"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="textView" destination="rN1-HL-YHv" id="gmr-Uf-jd8"/>
|
||||
<outlet property="textViewTopConstraint" destination="fiO-LL-nSC" id="Rum-TN-c2e"/>
|
||||
<outlet property="view" destination="9YG-0j-Zzg" id="jhb-eT-nEn"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="x1h-y1-h8q" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-2.1739130434782612" y="733.92857142857144"/>
|
||||
</scene>
|
||||
<!--Table View Controller For Adaptive Layout-->
|
||||
<scene sceneID="rDI-lU-wEx">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="TableViewControllerForAdaptiveLayout" id="5nC-6E-bXf" customClass="TableViewControllerForAdaptiveLayout" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="jXL-Ss-NCJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="W7W-ET-Wco" customClass="IntrinsicTableView" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" restorationIdentifier="Cell" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="Mqi-zK-WA7">
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Mqi-zK-WA7" id="X46-Fp-6Hr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="5nC-6E-bXf" id="RHg-aY-HNW"/>
|
||||
<outlet property="delegate" destination="5nC-6E-bXf" id="0YX-fh-bB8"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="ZfG-sd-dcQ"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="W7W-ET-Wco" firstAttribute="trailing" secondItem="ZfG-sd-dcQ" secondAttribute="trailing" id="3kP-rg-7c6"/>
|
||||
<constraint firstAttribute="bottom" secondItem="W7W-ET-Wco" secondAttribute="bottom" id="FdS-X9-D1D"/>
|
||||
<constraint firstItem="W7W-ET-Wco" firstAttribute="leading" secondItem="ZfG-sd-dcQ" secondAttribute="leading" id="HXa-oO-jag"/>
|
||||
<constraint firstItem="W7W-ET-Wco" firstAttribute="top" secondItem="jXL-Ss-NCJ" secondAttribute="top" id="gMX-Wq-7G8"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="tableView" destination="W7W-ET-Wco" id="N54-Fv-2Jq"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="7hJ-XW-9az" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4005" y="734"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<designables>
|
||||
<designable name="noi-1a-5bZ">
|
||||
<size key="intrinsicContentSize" width="30" height="30"/>
|
||||
</designable>
|
||||
</designables>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="r1P-2i-NDe"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<resources>
|
||||
<image name="IMG_0003" width="750" height="501"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemOrangeColor">
|
||||
<color red="1" green="0.58431372550000005" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemPurpleColor">
|
||||
<color red="0.68627450980000004" green="0.32156862749999998" blue="0.87058823529999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemTealColor">
|
||||
<color red="0.18823529410000001" green="0.69019607839999997" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
class CollectionViewControllerForAdaptiveLayout: UIViewController {
|
||||
class PanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
|
||||
private unowned var targetGuide: UILayoutGuide
|
||||
|
||||
init(targetGuide: UILayoutGuide) {
|
||||
self.targetGuide = targetGuide
|
||||
}
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelAdaptiveLayoutAnchor(
|
||||
absoluteOffset: 0.0,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview,
|
||||
contentBoundingGuide: .safeArea
|
||||
),
|
||||
.half: FloatingPanelAdaptiveLayoutAnchor(
|
||||
fractionalOffset: 0.5,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview,
|
||||
contentBoundingGuide: .safeArea
|
||||
),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
enum LayoutType {
|
||||
case flow
|
||||
case compositional
|
||||
}
|
||||
|
||||
weak var collectionView: UICollectionView!
|
||||
var layoutType: LayoutType = .flow
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setupCollectionView()
|
||||
}
|
||||
|
||||
private func setupCollectionView() {
|
||||
let collectionViewLayout = {
|
||||
switch layoutType {
|
||||
case .flow:
|
||||
CollectionViewLayoutFactory.flowLayout
|
||||
case .compositional:
|
||||
CollectionViewLayoutFactory.compositionalLayout
|
||||
}
|
||||
}()
|
||||
let collectionView = IntrinsicCollectionView(
|
||||
frame: .zero,
|
||||
collectionViewLayout: collectionViewLayout
|
||||
)
|
||||
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.backgroundColor = .yellow
|
||||
collectionView.register(Cell.self, forCellWithReuseIdentifier: Cell.reuseIdentifier)
|
||||
|
||||
view.addSubview(collectionView)
|
||||
self.collectionView = collectionView
|
||||
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
extension CollectionViewControllerForAdaptiveLayout: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return 5 // Only three cells needed to fill the space
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.reuseIdentifier, for: indexPath) as! Cell
|
||||
cell.configure(text: "Item \(indexPath.row)")
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
let width = collectionView.frame.width
|
||||
return CGSize(width: width, height: 100)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
extension CollectionViewControllerForAdaptiveLayout {
|
||||
enum CollectionViewLayoutFactory {
|
||||
static var flowLayout: UICollectionViewLayout {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.scrollDirection = .vertical
|
||||
layout.minimumLineSpacing = 8 // Vertical spacing between rows
|
||||
return layout
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
static var compositionalLayout: UICollectionViewLayout {
|
||||
UICollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
|
||||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(100))
|
||||
let item = NSCollectionLayoutItem(layoutSize: itemSize)
|
||||
|
||||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: itemSize, subitems: [item])
|
||||
|
||||
let section = NSCollectionLayoutSection(group: group)
|
||||
section.interGroupSpacing = 8 // Spacing between each group/item
|
||||
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
|
||||
|
||||
return section
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final class Cell: UICollectionViewCell {
|
||||
static let reuseIdentifier = "Cell"
|
||||
|
||||
private let label: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textAlignment = .center
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
commonInit()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
commonInit()
|
||||
}
|
||||
|
||||
private func commonInit() {
|
||||
backgroundColor = .systemBlue
|
||||
addSubview(label)
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
label.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
label.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
func configure(text: String) {
|
||||
label.text = text
|
||||
}
|
||||
}
|
||||
|
||||
private final class IntrinsicCollectionView: UICollectionView {
|
||||
override public var contentSize: CGSize {
|
||||
didSet {
|
||||
invalidateIntrinsicContentSize()
|
||||
}
|
||||
}
|
||||
|
||||
override public var intrinsicContentSize: CGSize {
|
||||
layoutIfNeeded()
|
||||
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class ImageViewController: UIViewController {
|
||||
class PanelLayout: FloatingPanelLayout {
|
||||
private unowned var targetGuide: UILayoutGuide
|
||||
init(targetGuide: UILayoutGuide) {
|
||||
self.targetGuide = targetGuide
|
||||
}
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelAdaptiveLayoutAnchor(
|
||||
absoluteOffset: 0,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview
|
||||
),
|
||||
.half: FloatingPanelAdaptiveLayoutAnchor(
|
||||
fractionalOffset: 0.5,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var headerView: UIView!
|
||||
@IBOutlet weak var footerView: UIView!
|
||||
@IBOutlet weak var scrollView: UIScrollView!
|
||||
@IBOutlet weak var stackView: UIStackView!
|
||||
|
||||
enum Mode {
|
||||
case onlyImage
|
||||
case withHeaderFooter
|
||||
}
|
||||
|
||||
func layoutGuideFor(mode: Mode) -> UILayoutGuide {
|
||||
switch mode {
|
||||
case .onlyImage:
|
||||
self.headerView.isHidden = true
|
||||
self.footerView.isHidden = true
|
||||
return scrollView.contentLayoutGuide
|
||||
case .withHeaderFooter:
|
||||
self.headerView.isHidden = false
|
||||
self.footerView.isHidden = false
|
||||
let guide = UILayoutGuide()
|
||||
view.addLayoutGuide(guide)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
scrollView.heightAnchor.constraint(equalTo: scrollView.contentLayoutGuide.heightAnchor),
|
||||
|
||||
guide.topAnchor.constraint(equalTo: stackView.topAnchor),
|
||||
guide.leftAnchor.constraint(equalTo: stackView.leftAnchor),
|
||||
guide.bottomAnchor.constraint(equalTo: stackView.bottomAnchor),
|
||||
guide.rightAnchor.constraint(equalTo: stackView.rightAnchor),
|
||||
])
|
||||
return guide
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class TableViewControllerForAdaptiveLayout: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
||||
class PanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
|
||||
private unowned var targetGuide: UILayoutGuide
|
||||
|
||||
init(targetGuide: UILayoutGuide) {
|
||||
self.targetGuide = targetGuide
|
||||
}
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelAdaptiveLayoutAnchor(
|
||||
absoluteOffset: 0.0,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview,
|
||||
contentBoundingGuide: .safeArea
|
||||
),
|
||||
.half: FloatingPanelAdaptiveLayoutAnchor(
|
||||
fractionalOffset: 0.5,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview,
|
||||
contentBoundingGuide: .safeArea
|
||||
),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var tableView: IntrinsicTableView!
|
||||
private let cellID = "Cell"
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
1
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
50
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
|
||||
cell.textLabel?.text = "\(indexPath.row)"
|
||||
return cell
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let headerView = UIView()
|
||||
headerView.backgroundColor = .orange
|
||||
return headerView
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
44.0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
40
|
||||
}
|
||||
}
|
||||
|
||||
class IntrinsicTableView: UITableView {
|
||||
override var contentSize:CGSize {
|
||||
didSet {
|
||||
invalidateIntrinsicContentSize()
|
||||
}
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
layoutIfNeeded()
|
||||
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
@available(iOS 14, *)
|
||||
class DebugListCollectionViewController: UIViewController {
|
||||
|
||||
enum Section {
|
||||
case main
|
||||
}
|
||||
|
||||
var dataSource: UICollectionViewDiffableDataSource<Section, Int>! = nil
|
||||
var collectionView: UICollectionView! = nil
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
navigationItem.title = "List"
|
||||
configureHierarchy()
|
||||
configureDataSource()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
extension DebugListCollectionViewController {
|
||||
/// - Tag: List
|
||||
private func createLayout() -> UICollectionViewLayout {
|
||||
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
|
||||
config.trailingSwipeActionsConfigurationProvider = { indexPath -> UISwipeActionsConfiguration? in
|
||||
return UISwipeActionsConfiguration(
|
||||
actions: [UIContextualAction(
|
||||
style: .destructive,
|
||||
title: "Delete",
|
||||
handler: { _, _, completion in
|
||||
// Do nothing now
|
||||
}
|
||||
)]
|
||||
)
|
||||
}
|
||||
return UICollectionViewCompositionalLayout.list(using: config)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
extension DebugListCollectionViewController {
|
||||
private func configureHierarchy() {
|
||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
|
||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
view.addSubview(collectionView)
|
||||
collectionView.delegate = self
|
||||
}
|
||||
private func configureDataSource() {
|
||||
|
||||
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
|
||||
var content = cell.defaultContentConfiguration()
|
||||
content.text = "\(item)"
|
||||
cell.contentConfiguration = content
|
||||
}
|
||||
|
||||
dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView) {
|
||||
(collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
|
||||
|
||||
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
|
||||
}
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
|
||||
snapshot.appendSections([.main])
|
||||
snapshot.appendItems(Array(0..<94))
|
||||
dataSource.apply(snapshot, animatingDifferences: false)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
extension DebugListCollectionViewController: UICollectionViewDelegate {
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
class DebugTableViewController: InspectableViewController {
|
||||
// MARK: - Views
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView(frame: .zero, style: .plain)
|
||||
tableView.dataSource = self
|
||||
tableView.delegate = self
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
|
||||
return tableView
|
||||
}()
|
||||
lazy var buttonStackView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .vertical
|
||||
stackView.distribution = .fillEqually
|
||||
stackView.alignment = .trailing
|
||||
stackView.spacing = 4
|
||||
return stackView
|
||||
}()
|
||||
private lazy var reorderButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setTitle(Menu.reorder.rawValue, for: .normal)
|
||||
button.setTitleColor(view.tintColor, for: .normal)
|
||||
button.addTarget(self, action: #selector(reorderItems), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
private lazy var trackingButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setTitle(Menu.trackScrolling.rawValue, for: .normal)
|
||||
button.setTitleColor(view.tintColor, for: .normal)
|
||||
button.addTarget(self, action: #selector(toggleTrackingScroll), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
private lazy var followingButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setTitleColor(view.tintColor, for: .normal)
|
||||
button.addTarget(self, action: #selector(toggleFollowingScroll), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var kvoObservers: [NSKeyValueObservation] = []
|
||||
|
||||
private var fpc: FloatingPanelController? { parent as? FloatingPanelController }
|
||||
private lazy var items: [String] = {
|
||||
let items = (0..<100).map { "Items \($0)" }
|
||||
return Command.replace(items: items)
|
||||
}()
|
||||
private var itemHeight: CGFloat = 66.0
|
||||
|
||||
// MARK: Flags
|
||||
private var tracksScrollView: Bool = false {
|
||||
didSet {
|
||||
let title = "\(Menu.trackScrolling.rawValue): \(tracksScrollView ? "on" : "off")"
|
||||
trackingButton.setTitle(title, for: .normal)
|
||||
}
|
||||
}
|
||||
private var followsScrollViewBouncing: Bool = false {
|
||||
didSet {
|
||||
let title = "\(Menu.followScrolling.rawValue): \(followsScrollViewBouncing ? "on" : "off")"
|
||||
followingButton.setTitle(title, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
enum Menu: String, CaseIterable {
|
||||
case trackScrolling = "Tracking"
|
||||
case followScrolling = "Following"
|
||||
case reorder = "Reorder"
|
||||
}
|
||||
|
||||
enum Command: Int, CaseIterable {
|
||||
case animateScroll
|
||||
case changeContentSize
|
||||
case moveToFull
|
||||
case moveToHalf
|
||||
var text: String {
|
||||
switch self {
|
||||
case .animateScroll: return "Scroll in the middle"
|
||||
case .changeContentSize: return "Change content size"
|
||||
case .moveToFull: return "Move to Full"
|
||||
case.moveToHalf: return "Move to Half"
|
||||
}
|
||||
}
|
||||
|
||||
static func replace(items: [String]) -> [String] {
|
||||
return items.enumerated().map { (index, text) -> String in
|
||||
if let action = Command(rawValue: index) {
|
||||
return "\(index). \(action.text)"
|
||||
}
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
func execute(for vc: DebugTableViewController, sourceView: UIView) {
|
||||
switch self {
|
||||
case .animateScroll:
|
||||
vc.animateScroll()
|
||||
case .changeContentSize:
|
||||
vc.changeContentSize(sourceView: sourceView)
|
||||
case .moveToFull:
|
||||
vc.moveToFull()
|
||||
case .moveToHalf:
|
||||
vc.moveToHalf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
layoutTableView()
|
||||
layoutMenuStackView()
|
||||
setUpMenu()
|
||||
}
|
||||
|
||||
private func layoutTableView() {
|
||||
view.addSubview(tableView)
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
tableView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
|
||||
tableView.rightAnchor.constraint(equalTo: view.rightAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func layoutMenuStackView() {
|
||||
view.addSubview(buttonStackView)
|
||||
buttonStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
buttonStackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 22.0),
|
||||
buttonStackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -22.0),
|
||||
])
|
||||
}
|
||||
|
||||
private func setUpMenu() {
|
||||
for menu in Menu.allCases {
|
||||
switch menu {
|
||||
case .reorder:
|
||||
buttonStackView.addArrangedSubview(reorderButton)
|
||||
case .trackScrolling:
|
||||
buttonStackView.addArrangedSubview(trackingButton)
|
||||
case .followScrolling:
|
||||
buttonStackView.addArrangedSubview(followingButton)
|
||||
}
|
||||
}
|
||||
// Set titles
|
||||
tracksScrollView = true
|
||||
followsScrollViewBouncing = false
|
||||
}
|
||||
|
||||
// MARK: - Menu
|
||||
|
||||
@objc
|
||||
private func reorderItems() {
|
||||
if reorderButton.titleLabel?.text == Menu.reorder.rawValue {
|
||||
tableView.isEditing = true
|
||||
reorderButton.setTitle("Cancel", for: .normal)
|
||||
} else {
|
||||
tableView.isEditing = false
|
||||
reorderButton.setTitle(Menu.reorder.rawValue, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func toggleTrackingScroll() {
|
||||
tracksScrollView.toggle()
|
||||
guard let fpc = fpc else { return }
|
||||
if tracksScrollView {
|
||||
fpc.track(scrollView: tableView)
|
||||
} else {
|
||||
fpc.untrack(scrollView: tableView)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func toggleFollowingScroll() {
|
||||
followsScrollViewBouncing.toggle()
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
private func execute(command: Command, sourceView: UIView) {
|
||||
command.execute(for: self, sourceView: sourceView)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func animateScroll() {
|
||||
tableView.scrollToRow(at: IndexPath(row: lround(Double(items.count) / 2.0),
|
||||
section: 0),
|
||||
at: .top, animated: true)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func changeContentSize(sourceView: UIView) {
|
||||
let actionSheet = UIAlertController(title: "Change content size", message: "", preferredStyle: .actionSheet)
|
||||
actionSheet.addAction(UIAlertAction(title: "Large", style: .default, handler: { (_) in
|
||||
self.itemHeight = 66.0
|
||||
self.changeItems(100)
|
||||
}))
|
||||
actionSheet.addAction(UIAlertAction(title: "Match", style: .default, handler: { (_) in
|
||||
switch self.tableView.bounds.height {
|
||||
case 585: // iPhone 6,7,8
|
||||
self.itemHeight = self.tableView.bounds.height / 13.0
|
||||
self.changeItems(13)
|
||||
case 656: // iPhone {6,7,8} Plus
|
||||
self.itemHeight = self.tableView.bounds.height / 16.0
|
||||
self.changeItems(16)
|
||||
default: // iPhone X family
|
||||
self.itemHeight = self.tableView.bounds.height / 12.0
|
||||
self.changeItems(12)
|
||||
}
|
||||
}))
|
||||
actionSheet.addAction(UIAlertAction(title: "Short", style: .default, handler: { (_) in
|
||||
self.itemHeight = 66.0
|
||||
self.changeItems(3)
|
||||
}))
|
||||
|
||||
if let popoverController = actionSheet.popoverPresentationController {
|
||||
popoverController.sourceView = sourceView
|
||||
popoverController.sourceRect = sourceView.bounds
|
||||
}
|
||||
|
||||
self.present(actionSheet, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
private func changeItems(_ count: Int) {
|
||||
items = Command.replace(items: (0..<count).map{ "\($0). No action" })
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
@objc
|
||||
private func moveToFull() {
|
||||
(self.parent as! FloatingPanelController).move(to: .full, animated: true)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func moveToHalf() {
|
||||
(self.parent as! FloatingPanelController).move(to: .half, animated: true)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func close(sender: UIButton) {
|
||||
// Remove FloatingPanel from a view
|
||||
(self.parent as! FloatingPanelController).removePanelFromParent(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension DebugTableViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return items.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
return itemHeight
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||
cell.textLabel?.text = items[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
extension DebugTableViewController: UITableViewDelegate {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if followsScrollViewBouncing {
|
||||
fpc?.followScrollViewBouncing()
|
||||
}
|
||||
print("TableView --- ", scrollView.contentOffset, scrollView.contentInset)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
print("DebugTableViewController -- select row \(indexPath.row)")
|
||||
guard let action = Command(rawValue: indexPath.row) else { return }
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
execute(command: action, sourceView: cell ?? tableView)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
|
||||
return [
|
||||
UITableViewRowAction(style: .destructive, title: "Delete", handler: { (action, path) in
|
||||
self.items.remove(at: path.row)
|
||||
tableView.deleteRows(at: [path], with: .automatic)
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
|
||||
items.insert(items.remove(at: sourceIndexPath.row), at: destinationIndexPath.row)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
final class DebugTextViewController: UIViewController, UITextViewDelegate {
|
||||
@IBOutlet weak var textView: UITextView!
|
||||
@IBOutlet weak var textViewTopConstraint: NSLayoutConstraint!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
textView.delegate = self
|
||||
print("viewDidLoad: TextView --- ", textView.contentOffset, textView.contentInset)
|
||||
|
||||
textView.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
|
||||
override func viewWillLayoutSubviews() {
|
||||
print("viewWillLayoutSubviews: TextView --- ", textView.contentOffset, textView.contentInset, textView.frame)
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
print("viewDidLayoutSubviews: TextView --- ", textView.contentOffset, textView.contentInset, textView.frame)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
print("TextView --- ", textView.contentOffset, textView.contentInset, textView.frame)
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
print("TextView --- ", scrollView.contentOffset, scrollView.contentInset)
|
||||
print("TextView --- ", scrollView.adjustedContentInset)
|
||||
}
|
||||
|
||||
@IBAction func toggleTopMargin(_ sender: UISwitch) {
|
||||
if sender.isOn {
|
||||
textViewTopConstraint.constant = 160
|
||||
} else {
|
||||
textViewTopConstraint.constant = 16
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func close(sender: UIButton) {
|
||||
// (self.parent as? FloatingPanelController)?.removePanelFromParent(animated: true, completion: nil)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class DetailViewController: InspectableViewController {
|
||||
@IBOutlet weak var modeChangeView: UIStackView!
|
||||
@IBOutlet weak var intrinsicHeightConstraint: NSLayoutConstraint!
|
||||
@IBOutlet weak var closeButton: UIButton!
|
||||
@IBAction func close(sender: UIButton) {
|
||||
// (self.parent as? FloatingPanelController)?.removePanelFromParent(animated: true, completion: nil)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func buttonPressed(_ sender: UIButton) {
|
||||
switch sender.titleLabel?.text {
|
||||
case "Show":
|
||||
performSegue(withIdentifier: "ShowSegue", sender: self)
|
||||
case "Present Modally":
|
||||
performSegue(withIdentifier: "PresentModallySegue", sender: self)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
@IBAction func modeChanged(_ sender: Any) {
|
||||
guard let fpc = parent as? FloatingPanelController else { return }
|
||||
fpc.contentMode = (fpc.contentMode == .static) ? .fitToBounds : .static
|
||||
}
|
||||
|
||||
@IBAction func tapped(_ sender: Any) {
|
||||
print("Detail panel is tapped!")
|
||||
}
|
||||
@IBAction func swipped(_ sender: Any) {
|
||||
print("Detail panel is swipped!")
|
||||
}
|
||||
@IBAction func longPressed(_ sender: Any) {
|
||||
print("Detail panel is longPressed!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
class InspectableViewController: UIViewController {
|
||||
override func viewWillLayoutSubviews() {
|
||||
super.viewWillLayoutSubviews()
|
||||
print(">>> Content View: viewWillLayoutSubviews", layoutInsets)
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
print(">>> Content View: viewDidLayoutSubviews", layoutInsets)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
print(">>> Content View: viewWillAppear", layoutInsets)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
print(">>> Content View: viewDidAppear", view.bounds, layoutInsets)
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
print(">>> Content View: viewWillDisappear")
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
print(">>> Content View: viewDidDisappear")
|
||||
}
|
||||
|
||||
override func willMove(toParent parent: UIViewController?) {
|
||||
super.willMove(toParent: parent)
|
||||
print(">>> Content View: willMove(toParent: \(String(describing: parent))")
|
||||
}
|
||||
|
||||
override func didMove(toParent parent: UIViewController?) {
|
||||
super.didMove(toParent: parent)
|
||||
print(">>> Content View: didMove(toParent: \(String(describing: parent))")
|
||||
}
|
||||
public override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
print(">>> Content View: willTransition(to: \(newCollection), with: \(coordinator))", layoutInsets)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class ModalViewController: UIViewController, FloatingPanelControllerDelegate {
|
||||
var fpc: FloatingPanelController!
|
||||
var consoleVC: DebugTextViewController!
|
||||
|
||||
@IBOutlet weak var safeAreaView: UIView!
|
||||
|
||||
var isNewlayout: Bool = false
|
||||
|
||||
override func viewDidLoad() {
|
||||
// Initialize FloatingPanelController
|
||||
fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
fpc.surfaceView.appearance = appearance
|
||||
|
||||
// Set a content view controller and track the scroll view
|
||||
let consoleVC = storyboard?.instantiateViewController(withIdentifier: "ConsoleViewController") as! DebugTextViewController
|
||||
fpc.set(contentViewController: consoleVC)
|
||||
fpc.track(scrollView: consoleVC.textView)
|
||||
|
||||
self.consoleVC = consoleVC
|
||||
|
||||
// Add FloatingPanel to self.view
|
||||
fpc.addPanel(toParent: self, at: view.subviews.firstIndex(of: safeAreaView) ?? -1)
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
// Remove FloatingPanel from a view
|
||||
fpc.removePanelFromParent(animated: false)
|
||||
}
|
||||
|
||||
@IBAction func close(sender: UIButton) {
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func moveToFull(sender: UIButton) {
|
||||
fpc.move(to: .full, animated: true)
|
||||
}
|
||||
@IBAction func moveToHalf(sender: UIButton) {
|
||||
fpc.move(to: .half, animated: true)
|
||||
}
|
||||
@IBAction func moveToTip(sender: UIButton) {
|
||||
fpc.move(to: .tip, animated: true)
|
||||
}
|
||||
@IBAction func moveToHidden(sender: UIButton) {
|
||||
fpc.move(to: .hidden, animated: true)
|
||||
}
|
||||
@IBAction func updateLayout(_ sender: Any) {
|
||||
isNewlayout = !isNewlayout
|
||||
UIView.animate(withDuration: 0.5) {
|
||||
self.fpc.invalidateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
return (isNewlayout) ? ModalSecondLayout() : FloatingPanelBottomLayout()
|
||||
}
|
||||
|
||||
class ModalSecondLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .half
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
import WebKit
|
||||
|
||||
final class MultiPanelController: FloatingPanelController, FloatingPanelControllerDelegate {
|
||||
|
||||
private final class FirstPanelContentViewController: UIViewController {
|
||||
|
||||
lazy var webView: WKWebView = WKWebView()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.addSubview(webView)
|
||||
webView.frame = view.bounds
|
||||
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
webView.load(URLRequest(url: URL(string: "https://www.apple.com")!))
|
||||
|
||||
let vc = MultiSecondPanelController()
|
||||
vc.setUpContent()
|
||||
vc.addPanel(toParent: self)
|
||||
}
|
||||
}
|
||||
|
||||
private final class MultiSecondPanelController: FloatingPanelController {
|
||||
|
||||
private final class SecondPanelContentViewController: DebugTableViewController {}
|
||||
|
||||
func setUpContent() {
|
||||
contentInsetAdjustmentBehavior = .never
|
||||
let vc = SecondPanelContentViewController()
|
||||
vc.loadViewIfNeeded()
|
||||
vc.title = "Second Panel"
|
||||
vc.buttonStackView.isHidden = true
|
||||
let navigationController = UINavigationController(rootViewController: vc)
|
||||
navigationController.navigationBar.barTintColor = .white
|
||||
navigationController.navigationBar.titleTextAttributes = [
|
||||
.foregroundColor: UIColor.black
|
||||
]
|
||||
set(contentViewController: navigationController)
|
||||
self.track(scrollView: vc.tableView)
|
||||
surfaceView.containerMargins = .init(top: 24.0, left: 0.0, bottom: layoutInsets.bottom, right: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
layout = FirstViewLayout()
|
||||
isRemovalInteractionEnabled = true
|
||||
|
||||
let vc = FirstPanelContentViewController()
|
||||
set(contentViewController: vc)
|
||||
track(scrollView: vc.webView.scrollView)
|
||||
}
|
||||
|
||||
private final class FirstViewLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 40.0, edge: .top, referenceGuide: .superview)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
final class NestedScrollViewController: UIViewController {
|
||||
@IBOutlet weak var scrollView: UIScrollView!
|
||||
@IBOutlet weak var nestedScrollView: UIScrollView!
|
||||
|
||||
@IBAction func longPressed(_ sender: Any) {
|
||||
print("LongPressed!")
|
||||
}
|
||||
@IBAction func swipped(_ sender: Any) {
|
||||
print("Swipped!")
|
||||
}
|
||||
@IBAction func tapped(_ sender: Any) {
|
||||
print("Tapped!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class SettingsViewController: InspectableViewController {
|
||||
@IBOutlet weak var largeTitlesSwitch: UISwitch!
|
||||
@IBOutlet weak var translucentSwitch: UISwitch!
|
||||
@IBOutlet weak var versionLabel: UILabel!
|
||||
|
||||
override func viewDidLoad() {
|
||||
versionLabel.text = "Version: \(Bundle.main.infoDictionary?["CFBundleVersion"] ?? "--")"
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
let prefersLargeTitles = navigationController!.navigationBar.prefersLargeTitles
|
||||
largeTitlesSwitch.setOn(prefersLargeTitles, animated: false)
|
||||
|
||||
let isTranslucent = navigationController!.navigationBar.isTranslucent
|
||||
translucentSwitch.setOn(isTranslucent, animated: false)
|
||||
}
|
||||
|
||||
@IBAction func toggleLargeTitle(_ sender: UISwitch) {
|
||||
navigationController?.navigationBar.prefersLargeTitles = sender.isOn
|
||||
}
|
||||
|
||||
@IBAction func toggleTranslucent(_ sender: UISwitch) {
|
||||
// White non-translucent navigation bar, supports dark appearance
|
||||
if #available(iOS 15, *) {
|
||||
let appearance = UINavigationBarAppearance()
|
||||
if sender.isOn {
|
||||
appearance.configureWithTransparentBackground()
|
||||
} else {
|
||||
appearance.configureWithOpaqueBackground()
|
||||
}
|
||||
navigationController?.navigationBar.standardAppearance = appearance
|
||||
navigationController?.navigationBar.scrollEdgeAppearance = appearance
|
||||
} else {
|
||||
navigationController?.navigationBar.isTranslucent = sender.isOn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class TabBarViewController: UITabBarController {}
|
||||
|
||||
final class TabBarContentViewController: UIViewController {
|
||||
enum Tab3Mode {
|
||||
case changeOffset
|
||||
case changeAutoLayout
|
||||
var label: String {
|
||||
switch self {
|
||||
case .changeAutoLayout: return "Use AutoLayout(OK)"
|
||||
case .changeOffset: return "Use ContentOffset(NG)"
|
||||
}
|
||||
}
|
||||
}
|
||||
lazy var fpc = FloatingPanelController()
|
||||
var consoleVC: DebugTextViewController!
|
||||
|
||||
var threeLayout: ThreeTabBarPanelLayout!
|
||||
var tab3Mode: Tab3Mode = .changeAutoLayout
|
||||
var switcherLabel: UILabel!
|
||||
|
||||
override func viewDidLoad() {
|
||||
fpc.delegate = self
|
||||
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
fpc.surfaceView.appearance = appearance
|
||||
|
||||
// Set a content view controller and track the scroll view
|
||||
let consoleVC = storyboard?.instantiateViewController(withIdentifier: "ConsoleViewController") as! DebugTextViewController
|
||||
fpc.set(contentViewController: consoleVC)
|
||||
consoleVC.textView.delegate = self // MUST call it before fpc.track(scrollView:)
|
||||
fpc.track(scrollView: consoleVC.textView)
|
||||
self.consoleVC = consoleVC
|
||||
|
||||
// Add FloatingPanel to self.view
|
||||
fpc.addPanel(toParent: self)
|
||||
|
||||
|
||||
if #available(iOS 15, *) {
|
||||
tabBarController?.tabBar.scrollEdgeAppearance = UITabBarAppearance()
|
||||
}
|
||||
|
||||
switch tabBarItem.tag {
|
||||
case 1:
|
||||
fpc.behavior = TwoTabBarPanelBehavior()
|
||||
case 2:
|
||||
let switcher = UISwitch()
|
||||
fpc.view.addSubview(switcher)
|
||||
switcher.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
switcher.bottomAnchor.constraint(equalTo: fpc.surfaceView.topAnchor, constant: -16.0),
|
||||
switcher.rightAnchor.constraint(equalTo: fpc.surfaceView.rightAnchor, constant: -16.0),
|
||||
])
|
||||
switcher.isOn = true
|
||||
switcher.tintColor = .white
|
||||
switcher.backgroundColor = .white
|
||||
switcher.layer.cornerRadius = 16.0
|
||||
switcher.addTarget(self,
|
||||
action: #selector(changeTab3Mode(_:)),
|
||||
for: .valueChanged)
|
||||
let label = UILabel()
|
||||
label.text = tab3Mode.label
|
||||
fpc.view.addSubview(label)
|
||||
switcherLabel = label
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
label.centerYAnchor.constraint(equalTo: switcher.centerYAnchor, constant: 0.0),
|
||||
label.rightAnchor.constraint(equalTo: switcher.leftAnchor, constant: -16.0),
|
||||
])
|
||||
|
||||
// Turn off the mask instead of content inset change
|
||||
consoleVC.textView.clipsToBounds = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
fpc.invalidateLayout()
|
||||
}
|
||||
|
||||
// MARK: - Action
|
||||
|
||||
@IBAction func close(sender: UIButton) {
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@objc
|
||||
private func changeTab3Mode(_ sender: UISwitch) {
|
||||
if sender.isOn {
|
||||
tab3Mode = .changeAutoLayout
|
||||
} else {
|
||||
tab3Mode = .changeOffset
|
||||
}
|
||||
switcherLabel.text = tab3Mode.label
|
||||
}
|
||||
}
|
||||
|
||||
extension TabBarContentViewController: UITextViewDelegate {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
guard self.tabBarItem.tag == 2 else { return }
|
||||
// Reset an invalid content offset by a user after updating the layout
|
||||
// of `consoleVC.textView`.
|
||||
// NOTE: FloatingPanel doesn't implicitly reset the offset(i.e.
|
||||
// Using KVO of `scrollView.contentOffset`). Because it can lead to an
|
||||
// infinite loop if a user also resets a content offset as below and,
|
||||
// in the situation, a user has to modify the library.
|
||||
if fpc.state != .full, fpc.surfaceLocation.y > fpc.surfaceLocation(for: .full).y {
|
||||
scrollView.contentOffset = .zero
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TabBarContentViewController: FloatingPanelControllerDelegate {
|
||||
// MARK: - FloatingPanel
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
switch self.tabBarItem.tag {
|
||||
case 0:
|
||||
return OneTabBarPanelLayout()
|
||||
case 1:
|
||||
return TwoTabBarPanelLayout()
|
||||
case 2:
|
||||
threeLayout = ThreeTabBarPanelLayout(parent: self)
|
||||
return threeLayout
|
||||
default:
|
||||
return FloatingPanelBottomLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelDidMove(_ vc: FloatingPanelController) {
|
||||
guard self.tabBarItem.tag == 2 else { return }
|
||||
switch tab3Mode {
|
||||
case .changeAutoLayout:
|
||||
/* Good solution: Manipulate top constraint */
|
||||
assert(consoleVC.textViewTopConstraint != nil)
|
||||
let safeAreaTop = vc.layoutInsets.top
|
||||
if vc.surfaceLocation.y + threeLayout.topPadding < safeAreaTop {
|
||||
consoleVC.textViewTopConstraint?.constant = min(safeAreaTop - vc.surfaceLocation.y,
|
||||
safeAreaTop)
|
||||
} else {
|
||||
consoleVC.textViewTopConstraint?.constant = threeLayout.topPadding
|
||||
}
|
||||
case .changeOffset:
|
||||
/*
|
||||
Bad solution: Manipulate scroll content inset
|
||||
|
||||
FloatingPanelController keeps a content offset in moving a panel
|
||||
so that changing content inset or offset causes a buggy behavior.
|
||||
*/
|
||||
guard let scrollView = consoleVC.textView else { return }
|
||||
var insets = vc.adjustedContentInsets
|
||||
if vc.surfaceView.frame.minY < vc.layoutInsets.top {
|
||||
insets.top = vc.layoutInsets.top - vc.surfaceView.frame.minY
|
||||
} else {
|
||||
insets.top = 0.0
|
||||
}
|
||||
scrollView.contentInset = insets
|
||||
|
||||
if vc.surfaceView.frame.minY > 0 {
|
||||
scrollView.contentOffset = CGPoint(x: 0.0,
|
||||
y: 0.0 - scrollView.contentInset.top)
|
||||
}
|
||||
}
|
||||
|
||||
if vc.surfaceLocation.y > vc.surfaceLocation(for: .half).y {
|
||||
let progress = (vc.surfaceLocation.y - vc.surfaceLocation(for: .half).y)
|
||||
/ (vc.surfaceLocation(for: .tip).y - vc.surfaceLocation(for: .half).y)
|
||||
threeLayout.leftConstraint.constant = max(min(progress, 1.0), 0.0) * threeLayout.sideMargin
|
||||
threeLayout.rightConstraint.constant = -max(min(progress, 1.0), 0.0) * threeLayout.sideMargin
|
||||
} else {
|
||||
threeLayout.leftConstraint.constant = 0.0
|
||||
threeLayout.rightConstraint.constant = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OneTabBarPanelLayout: FloatingPanelLayout {
|
||||
var initialState: FloatingPanelState { .tip }
|
||||
var position: FloatingPanelPosition { .bottom }
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 22.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class TwoTabBarPanelLayout: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .half
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 100.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 261.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
|
||||
class TwoTabBarPanelBehavior: FloatingPanelBehavior {
|
||||
func allowsRubberBanding(for edges: UIRectEdge) -> Bool {
|
||||
return [UIRectEdge.top, UIRectEdge.bottom].contains(edges)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ThreeTabBarPanelLayout: FloatingPanelLayout {
|
||||
weak var parentVC: UIViewController!
|
||||
|
||||
var leftConstraint: NSLayoutConstraint!
|
||||
var rightConstraint: NSLayoutConstraint!
|
||||
|
||||
let topPadding: CGFloat = 17.0
|
||||
let sideMargin: CGFloat = 16.0
|
||||
|
||||
init(parent: UIViewController) {
|
||||
parentVC = parent
|
||||
}
|
||||
|
||||
var initialState: FloatingPanelState { .half }
|
||||
var position: FloatingPanelPosition { .bottom }
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 0.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 261.0 + parentVC.layoutInsets.bottom, edge: .bottom, referenceGuide: .superview),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 88.0 + parentVC.layoutInsets.bottom, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
}
|
||||
|
||||
func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
leftConstraint = surfaceView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0.0)
|
||||
rightConstraint = surfaceView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: 0.0)
|
||||
return [ leftConstraint, rightConstraint ]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
class UnavailableViewController: UIViewController {
|
||||
weak var label: UILabel!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let label = UILabel()
|
||||
label.text = "Unavailable content"
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
label.frame = view.bounds
|
||||
label.autoresizingMask = [
|
||||
.flexibleTopMargin,
|
||||
.flexibleLeftMargin,
|
||||
.flexibleBottomMargin,
|
||||
.flexibleRightMargin
|
||||
]
|
||||
view.addSubview(label)
|
||||
self.label = label
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import Foundation
|
||||
import FloatingPanel
|
||||
|
||||
extension FloatingPanelState {
|
||||
static let lastQuart: FloatingPanelState = FloatingPanelState(rawValue: "lastQuart", order: 750)
|
||||
static let firstQuart: FloatingPanelState = FloatingPanelState(rawValue: "firstQuart", order: 250)
|
||||
}
|
||||
|
||||
class FloatingPanelLayoutWithCustomState: FloatingPanelBottomLayout {
|
||||
override var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 0.0, edge: .top, referenceGuide: .safeArea),
|
||||
.lastQuart: FloatingPanelLayoutAnchor(fractionalInset: 0.75, edge: .bottom, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.firstQuart: FloatingPanelLayoutAnchor(fractionalInset: 0.25, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
func makeBoundsLayoutGuide() -> UILayoutGuide {
|
||||
let guide = UILayoutGuide()
|
||||
addLayoutGuide(guide)
|
||||
NSLayoutConstraint.activate([
|
||||
guide.topAnchor.constraint(equalTo: topAnchor),
|
||||
guide.leftAnchor.constraint(equalTo: leftAnchor),
|
||||
guide.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
guide.rightAnchor.constraint(equalTo: rightAnchor),
|
||||
])
|
||||
return guide
|
||||
}
|
||||
}
|
||||
|
||||
protocol LayoutGuideProvider {
|
||||
var topAnchor: NSLayoutYAxisAnchor { get }
|
||||
var bottomAnchor: NSLayoutYAxisAnchor { get }
|
||||
}
|
||||
extension UILayoutGuide: LayoutGuideProvider {}
|
||||
|
||||
class CustomLayoutGuide: LayoutGuideProvider {
|
||||
let topAnchor: NSLayoutYAxisAnchor
|
||||
let bottomAnchor: NSLayoutYAxisAnchor
|
||||
init(topAnchor: NSLayoutYAxisAnchor, bottomAnchor: NSLayoutYAxisAnchor) {
|
||||
self.topAnchor = topAnchor
|
||||
self.bottomAnchor = bottomAnchor
|
||||
}
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
var layoutInsets: UIEdgeInsets {
|
||||
return view.safeAreaInsets
|
||||
}
|
||||
|
||||
var layoutGuide: LayoutGuideProvider {
|
||||
return view.safeAreaLayoutGuide
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class MainViewController: UIViewController {
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
private var observations: [NSKeyValueObservation] = []
|
||||
private lazy var useCaseController = UseCaseController(mainVC: self)
|
||||
}
|
||||
|
||||
extension MainViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.dataSource = self
|
||||
tableView.delegate = self
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
|
||||
|
||||
let searchController = UISearchController(searchResultsController: nil)
|
||||
navigationItem.searchController = searchController
|
||||
navigationItem.hidesSearchBarWhenScrolling = false
|
||||
navigationItem.largeTitleDisplayMode = .automatic
|
||||
var insets = UIEdgeInsets.zero
|
||||
insets.bottom += 69.0
|
||||
tableView.contentInset = insets
|
||||
|
||||
// Show the initial panel
|
||||
useCaseController.set(useCase: .trackingTableView)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
if let observation = navigationController?.navigationBar.observe(\.prefersLargeTitles, changeHandler: { (bar, _) in
|
||||
self.tableView.reloadData()
|
||||
}) {
|
||||
observations.append(observation)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
observations.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
extension MainViewController {
|
||||
@IBAction func showDebugMenu(_ sender: UIBarButtonItem) {
|
||||
useCaseController.setUpSettingsPanel(for: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension MainViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
if navigationController?.navigationBar.prefersLargeTitles == true {
|
||||
return UseCase.allCases.count + 30
|
||||
} else {
|
||||
return UseCase.allCases.count
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||
if UseCase.allCases.count > indexPath.row {
|
||||
let menu = UseCase.allCases[indexPath.row]
|
||||
cell.textLabel?.text = menu.name
|
||||
} else {
|
||||
cell.textLabel?.text = "\(indexPath.row) row"
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
extension MainViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard UseCase.allCases.count > indexPath.row else { return }
|
||||
|
||||
// Change panels
|
||||
useCaseController.set(useCase: UseCase.allCases[indexPath.row])
|
||||
}
|
||||
|
||||
@objc func dismissPresentedVC() {
|
||||
self.presentedViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
/**
|
||||
- Attention: `FloatingPanelLayout` must not be applied by the parent view
|
||||
controller of a panel. But here `MainViewController` adopts it
|
||||
purposely to check if the library prints an appropriate warning.
|
||||
*/
|
||||
extension MainViewController: FloatingPanelLayout {
|
||||
var position: FloatingPanelPosition { .bottom }
|
||||
var initialState: FloatingPanelState { .half }
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: UIScreen.main.bounds.height == 667.0 ? 18.0 : 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class TopPositionedPanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .top
|
||||
let initialState: FloatingPanelState = .full
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 88.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 216.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .top, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
|
||||
class IntrinsicPanelLayout: FloatingPanelBottomLayout {
|
||||
override var initialState: FloatingPanelState { .full }
|
||||
override var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.0, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class RemovablePanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .half
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 130.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
}
|
||||
}
|
||||
|
||||
class RemovablePanelLandscapeLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 216.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
}
|
||||
}
|
||||
|
||||
class ModalPanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(absoluteOffset: 0.0, referenceGuide: .safeArea),
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
final class CloseButton: UIButton {
|
||||
override var isHighlighted: Bool { didSet { setNeedsDisplay() } }
|
||||
override var isSelected: Bool { didSet { setNeedsDisplay() } }
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
render()
|
||||
}
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
render()
|
||||
}
|
||||
|
||||
func render() {
|
||||
self.backgroundColor = .clear
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
func p(_ p: CGFloat) -> CGFloat {
|
||||
return p * (2.0 / 3.0)
|
||||
}
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
context.setLineWidth(p(1.0))
|
||||
|
||||
let color = UIColor(displayP3Red: 0.76,
|
||||
green: 0.77,
|
||||
blue: 0.76,
|
||||
alpha: 1.0)
|
||||
|
||||
context.setFillColor(color.cgColor)
|
||||
|
||||
context.beginPath()
|
||||
context.addArc(center: CGPoint(x: rect.width * 0.5,
|
||||
y: rect.height * 0.5),
|
||||
radius: p(36.0) * 0.5,
|
||||
startAngle: 0,
|
||||
endAngle: CGFloat.pi * 2.0,
|
||||
clockwise: true)
|
||||
context.fillPath()
|
||||
|
||||
let highlightedColor = UIColor(displayP3Red: 0.53,
|
||||
green: 0.53,
|
||||
blue: 0.53,
|
||||
alpha: 1.0)
|
||||
|
||||
let crossColor: UIColor = isHighlighted || isSelected ? highlightedColor : .white
|
||||
context.setStrokeColor(crossColor.cgColor)
|
||||
context.setBlendMode(.normal)
|
||||
context.setLineWidth(p(3.5))
|
||||
context.setLineCap(.round)
|
||||
|
||||
let offset = (rect.width - p(36.0)) * 0.5
|
||||
|
||||
context.beginPath()
|
||||
context.addLines(between: [CGPoint(x: offset + p(12.0), y: offset + p(12.0)),
|
||||
CGPoint(x: offset + p(24.0), y: offset + p(24.0))])
|
||||
context.strokePath()
|
||||
|
||||
context.beginPath()
|
||||
context.addLines(between: [CGPoint(x: offset + p(24.0), y: offset + p(12.0)),
|
||||
CGPoint(x: offset + p(12.0), y: offset + p(24.0))])
|
||||
context.strokePath()
|
||||
}
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
final class SafeAreaView: UIView {
|
||||
override func prepareForInterfaceBuilder() {
|
||||
let label = UILabel()
|
||||
label.text = "Safe Area"
|
||||
addSubview(label)
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
label.centerXAnchor.constraint(equalTo: self.centerXAnchor),
|
||||
label.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: -4.0),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBDesignable
|
||||
final class OnSafeAreaView: UIView {
|
||||
override func prepareForInterfaceBuilder() {
|
||||
let label = UILabel()
|
||||
label.text = "On Safe Area"
|
||||
addSubview(label)
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
label.centerXAnchor.constraint(equalTo: self.centerXAnchor),
|
||||
label.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: -4.0),
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class PagePanelController: NSObject {
|
||||
var pages: [UIViewController] = []
|
||||
}
|
||||
|
||||
extension PagePanelController {
|
||||
func makePageViewControllerForContent() -> UIPageViewController {
|
||||
pages = [DebugTableViewController(), DebugTableViewController(), DebugTableViewController()]
|
||||
let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
|
||||
pageVC.dataSource = self
|
||||
pageVC.delegate = self
|
||||
pageVC.setViewControllers([pages[0]], direction: .forward, animated: false, completion: nil)
|
||||
return pageVC
|
||||
}
|
||||
|
||||
func makePageViewController(for vc: MainViewController) -> UIPageViewController {
|
||||
pages = [UIColor.blue, .red, .green].compactMap({ (color) -> UIViewController in
|
||||
let page = FloatingPanelController(delegate: self)
|
||||
page.view.backgroundColor = color
|
||||
page.panGestureRecognizer.delegateProxy = self
|
||||
page.show()
|
||||
return page
|
||||
})
|
||||
let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
|
||||
let closeButton = UIButton(type: .custom)
|
||||
pageVC.view.addSubview(closeButton)
|
||||
closeButton.setTitle("Close", for: .normal)
|
||||
closeButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
closeButton.addTarget(vc, action: #selector(MainViewController.dismissPresentedVC), for: .touchUpInside)
|
||||
NSLayoutConstraint.activate([
|
||||
closeButton.topAnchor.constraint(equalTo: pageVC.layoutGuide.topAnchor, constant: 16.0),
|
||||
closeButton.leftAnchor.constraint(equalTo: pageVC.view.leftAnchor, constant: 16.0),
|
||||
])
|
||||
pageVC.dataSource = self
|
||||
pageVC.setViewControllers([pages[0]], direction: .forward, animated: false, completion: nil)
|
||||
pageVC.modalPresentationStyle = .fullScreen
|
||||
return pageVC
|
||||
}
|
||||
}
|
||||
|
||||
extension PagePanelController: FloatingPanelControllerDelegate {
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
return FloatingPanelBottomLayout()
|
||||
}
|
||||
}
|
||||
|
||||
extension PagePanelController: UIGestureRecognizerDelegate {
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension PagePanelController: UIPageViewControllerDataSource {
|
||||
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
|
||||
guard
|
||||
let index = pages.firstIndex(of: viewController),
|
||||
index + 1 < pages.count
|
||||
else { return nil }
|
||||
return pages[index + 1]
|
||||
}
|
||||
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
||||
guard
|
||||
let index = pages.firstIndex(of: viewController),
|
||||
index - 1 >= 0
|
||||
else { return nil }
|
||||
return pages[index - 1]
|
||||
}
|
||||
}
|
||||
|
||||
extension PagePanelController: UIPageViewControllerDelegate {
|
||||
// For showPageContent
|
||||
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
|
||||
if completed, let page = pageViewController.viewControllers?.first {
|
||||
(pageViewController.parent as! FloatingPanelController).track(scrollView: (page as! DebugTableViewController).tableView)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
enum UseCase: Int, CaseIterable {
|
||||
case trackingTableView
|
||||
case trackingTextView
|
||||
case trackingCollectionViewList
|
||||
case showDetail
|
||||
case showModal
|
||||
case showPanelModal
|
||||
case showMultiPanelModal
|
||||
case showPanelInSheetModal
|
||||
case showOnWindow
|
||||
case showTabBar
|
||||
case showPageView
|
||||
case showPageContentView
|
||||
case showNestedScrollView
|
||||
case showRemovablePanel
|
||||
case showIntrinsicView
|
||||
case showContentInset
|
||||
case showContainerMargins
|
||||
case showNavigationController
|
||||
case showTopPositionedPanel
|
||||
case showAdaptivePanel
|
||||
case showAdaptivePanelWithTableView
|
||||
case showAdaptivePanelWithCollectionView
|
||||
case showAdaptivePanelWithCompositionalCollectionView
|
||||
case showCustomStatePanel
|
||||
case showCustomBackdrop
|
||||
}
|
||||
|
||||
extension UseCase {
|
||||
var name: String {
|
||||
switch self {
|
||||
case .trackingTableView: return "Scroll tracking(TableView)"
|
||||
case .trackingCollectionViewList: return "Scroll tracking(List CollectionView)"
|
||||
case .trackingTextView: return "Scroll tracking(TextView)"
|
||||
case .showDetail: return "Show Detail Panel"
|
||||
case .showModal: return "Show Modal"
|
||||
case .showPanelModal: return "Show Panel Modal"
|
||||
case .showMultiPanelModal: return "Show Multi Panel Modal"
|
||||
case .showOnWindow: return "Show Panel over Window"
|
||||
case .showPanelInSheetModal: return "Show Panel in Sheet Modal"
|
||||
case .showTabBar: return "Show Tab Bar"
|
||||
case .showPageView: return "Show Page View"
|
||||
case .showPageContentView: return "Show Page Content View"
|
||||
case .showNestedScrollView: return "Show Nested ScrollView"
|
||||
case .showRemovablePanel: return "Show Removable Panel"
|
||||
case .showIntrinsicView: return "Show Intrinsic View"
|
||||
case .showContentInset: return "Show with ContentInset"
|
||||
case .showContainerMargins: return "Show with ContainerMargins"
|
||||
case .showNavigationController: return "Show Navigation Controller"
|
||||
case .showTopPositionedPanel: return "Show Top Positioned Panel"
|
||||
case .showAdaptivePanel: return "Show Adaptive Panel"
|
||||
case .showAdaptivePanelWithTableView: return "Show Adaptive Panel (TableView)"
|
||||
case .showAdaptivePanelWithCollectionView: return "Show Adaptive Panel (CollectionView)"
|
||||
case .showAdaptivePanelWithCompositionalCollectionView: return "Show Adaptive Panel (Compositional CollectionView)"
|
||||
case .showCustomStatePanel: return "Show Panel with Custom state"
|
||||
case .showCustomBackdrop: return "Show Panel with Custom Backdrop"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UseCase {
|
||||
private enum Content {
|
||||
case storyboard(String)
|
||||
case viewController(UIViewController)
|
||||
}
|
||||
|
||||
private var content: Content {
|
||||
switch self {
|
||||
case .trackingTableView: return .viewController(DebugTableViewController())
|
||||
case .trackingCollectionViewList:
|
||||
if #available(iOS 14, *) {
|
||||
return .viewController(DebugListCollectionViewController())
|
||||
} else {
|
||||
let msg = "UICollectionLayoutListConfiguration is unavailable.\nBuild this app on iOS 14 and later."
|
||||
return makeUnavailableViewContent(message: msg)
|
||||
}
|
||||
case .trackingTextView: return .storyboard("ConsoleViewController") // Storyboard only
|
||||
case .showDetail: return .storyboard(String(describing: DetailViewController.self))
|
||||
case .showModal: return .storyboard(String(describing: ModalViewController.self))
|
||||
case .showMultiPanelModal: return .viewController(DebugTableViewController())
|
||||
case .showOnWindow: return .viewController(DebugTableViewController())
|
||||
case .showPanelInSheetModal: return .viewController(DebugTableViewController())
|
||||
case .showPanelModal: return .viewController(DebugTableViewController())
|
||||
case .showTabBar: return .storyboard(String(describing: TabBarViewController.self))
|
||||
case .showPageView: return .viewController(DebugTableViewController())
|
||||
case .showPageContentView: return .viewController(DebugTableViewController())
|
||||
case .showNestedScrollView: return .storyboard(String(describing: NestedScrollViewController.self))
|
||||
case .showRemovablePanel: return .storyboard(String(describing: DetailViewController.self))
|
||||
case .showIntrinsicView: return .storyboard("IntrinsicViewController") // Storyboard only
|
||||
case .showContentInset: return .viewController(DebugTableViewController())
|
||||
case .showContainerMargins: return .viewController(DebugTableViewController())
|
||||
case .showNavigationController: return .storyboard("RootNavigationController") // Storyboard only
|
||||
case .showTopPositionedPanel: return .viewController(DebugTableViewController())
|
||||
case .showAdaptivePanel: return .storyboard(String(describing: ImageViewController.self))
|
||||
case .showAdaptivePanelWithTableView: return .storyboard(String(describing: TableViewControllerForAdaptiveLayout.self))
|
||||
case .showAdaptivePanelWithCollectionView,
|
||||
.showAdaptivePanelWithCompositionalCollectionView:
|
||||
if #available(iOS 13, *) {
|
||||
let vc = CollectionViewControllerForAdaptiveLayout()
|
||||
vc.layoutType = self == .showAdaptivePanelWithCollectionView ? .flow : .compositional
|
||||
return .viewController(vc)
|
||||
} else {
|
||||
let msg = "Compositional layout is unavailable.\nBuild this app on iOS 13 and later."
|
||||
return makeUnavailableViewContent(message: msg)
|
||||
}
|
||||
case .showCustomStatePanel: return .viewController(DebugTableViewController())
|
||||
case .showCustomBackdrop: return .viewController(UIViewController())
|
||||
}
|
||||
}
|
||||
|
||||
func makeContentViewController(with storyboard: UIStoryboard) -> UIViewController {
|
||||
switch content {
|
||||
case .storyboard(let id):
|
||||
return storyboard.instantiateViewController(withIdentifier: id)
|
||||
case .viewController(let vc):
|
||||
vc.loadViewIfNeeded()
|
||||
return vc
|
||||
}
|
||||
}
|
||||
|
||||
private func makeUnavailableViewContent(message: String) -> Content {
|
||||
let vc = UnavailableViewController()
|
||||
vc.loadViewIfNeeded()
|
||||
vc.label.text = message
|
||||
return .viewController(vc)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class UseCaseController: NSObject {
|
||||
unowned let mainVC: MainViewController
|
||||
private(set) var useCase: UseCase
|
||||
|
||||
private var mainPanelVC: FloatingPanelController!
|
||||
private var detailPanelVC: FloatingPanelController!
|
||||
private var settingsPanelVC: FloatingPanelController!
|
||||
private lazy var pagePanelController = PagePanelController()
|
||||
private lazy var overWindowPanelVC = FloatingPanelController()
|
||||
|
||||
init(mainVC: MainViewController) {
|
||||
self.mainVC = mainVC
|
||||
self.useCase = .trackingTableView
|
||||
}
|
||||
}
|
||||
|
||||
extension UseCaseController {
|
||||
func set(useCase: UseCase) {
|
||||
self.useCase = useCase
|
||||
|
||||
let contentVC = useCase.makeContentViewController(with: mainVC.storyboard!)
|
||||
|
||||
if let fpc = detailPanelVC {
|
||||
fpc.removePanelFromParent(animated: true, completion: nil)
|
||||
self.detailPanelVC = nil
|
||||
}
|
||||
|
||||
switch useCase {
|
||||
case .trackingTableView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(UseCaseController.handleSurface(tapGesture:)))
|
||||
tapGesture.cancelsTouchesInView = false
|
||||
tapGesture.numberOfTapsRequired = 2
|
||||
// Prevents a delay to response a tap in menus of DebugTableViewController.
|
||||
tapGesture.delaysTouchesEnded = false
|
||||
fpc.surfaceView.addGestureRecognizer(tapGesture)
|
||||
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .trackingCollectionViewList:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(UseCaseController.handleSurface(tapGesture:)))
|
||||
tapGesture.cancelsTouchesInView = false
|
||||
tapGesture.numberOfTapsRequired = 2
|
||||
// Prevents a delay to response a tap in menus of DebugTableViewController.
|
||||
tapGesture.delaysTouchesEnded = false
|
||||
fpc.surfaceView.addGestureRecognizer(tapGesture)
|
||||
|
||||
fpc.set(contentViewController: contentVC)
|
||||
if #available(iOS 14, *),
|
||||
let scrollView = (fpc.contentViewController as? DebugListCollectionViewController)?.collectionView {
|
||||
fpc.track(scrollView: scrollView)
|
||||
}
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .trackingTextView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showDetail:
|
||||
// Initialize FloatingPanelController
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
// Set a content view controller
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.contentMode = .fitToBounds
|
||||
(contentVC as? DetailViewController)?.intrinsicHeightConstraint.isActive = false
|
||||
|
||||
detailPanelVC = fpc
|
||||
// Add FloatingPanel to self.view
|
||||
fpc.addPanel(toParent: mainVC, animated: true)
|
||||
|
||||
case .showModal, .showTabBar:
|
||||
let modalVC = contentVC
|
||||
modalVC.modalPresentationStyle = .fullScreen
|
||||
mainVC.present(modalVC, animated: true, completion: nil)
|
||||
|
||||
case .showPageView:
|
||||
let pageVC = pagePanelController.makePageViewController(for: mainVC)
|
||||
mainVC.present(pageVC, animated: true, completion: nil)
|
||||
|
||||
case .showPageContentView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
let pageVC = pagePanelController.makePageViewControllerForContent()
|
||||
if let page = (fpc.contentViewController as? UIPageViewController)?.viewControllers?.first {
|
||||
fpc.track(scrollView: (page as! DebugTableViewController).tableView)
|
||||
}
|
||||
fpc.set(contentViewController: pageVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showRemovablePanel, .showIntrinsicView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
fpc.backdropView.dismissalTapGestureRecognizer.isEnabled = true
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showNestedScrollView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.panGestureRecognizer.delegateProxy = self
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showPanelModal:
|
||||
let fpc = FloatingPanelController()
|
||||
let contentVC = mainVC.storyboard!.instantiateViewController(withIdentifier: "DetailViewController")
|
||||
contentVC.loadViewIfNeeded()
|
||||
(contentVC as? DetailViewController)?.modeChangeView.isHidden = true
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.delegate = self
|
||||
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 38.5
|
||||
fpc.surfaceView.appearance = appearance
|
||||
fpc.backdropView.dismissalTapGestureRecognizer.isEnabled = true
|
||||
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
|
||||
mainVC.present(fpc, animated: true, completion: nil)
|
||||
|
||||
case .showMultiPanelModal:
|
||||
let fpc = MultiPanelController()
|
||||
mainVC.present(fpc, animated: true, completion: nil)
|
||||
|
||||
case .showOnWindow:
|
||||
let fpc = overWindowPanelVC
|
||||
fpc.backdropView.dismissalTapGestureRecognizer.isEnabled = true
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
|
||||
guard let window = UIApplication.shared.windows.first else { fatalError("Any window not found") }
|
||||
|
||||
window.addSubview(fpc.view)
|
||||
fpc.view.frame = window.bounds
|
||||
fpc.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
fpc.show(animated: true)
|
||||
case .showPanelInSheetModal:
|
||||
let fpc = FloatingPanelController()
|
||||
let contentVC = UIViewController()
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.delegate = self
|
||||
|
||||
let apprearance = SurfaceAppearance()
|
||||
apprearance.cornerRadius = 38.5
|
||||
apprearance.shadows = []
|
||||
fpc.surfaceView.appearance = apprearance
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
|
||||
let mvc = UIViewController()
|
||||
mvc.view.backgroundColor = UIColor(displayP3Red: 2/255, green: 184/255, blue: 117/255, alpha: 1.0)
|
||||
fpc.addPanel(toParent: mvc)
|
||||
mainVC.present(mvc, animated: true, completion: nil)
|
||||
|
||||
case .showContentInset:
|
||||
let contentViewController = UIViewController()
|
||||
contentViewController.view.backgroundColor = .green
|
||||
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.set(contentViewController: contentViewController)
|
||||
fpc.surfaceView.contentPadding = .init(top: 20, left: 20, bottom: 20, right: 20)
|
||||
|
||||
fpc.delegate = self
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
mainVC.present(fpc, animated: true, completion: nil)
|
||||
|
||||
case .showContainerMargins:
|
||||
let fpc = FloatingPanelController()
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 38.5
|
||||
fpc.surfaceView.appearance = appearance
|
||||
|
||||
fpc.surfaceView.backgroundColor = .red
|
||||
fpc.surfaceView.containerMargins = .init(top: 24.0, left: 8.0, bottom: max(mainVC.layoutInsets.bottom, 8.0), right: 8.0)
|
||||
#if swift(>=5.1) // Actually Xcode 11 or later
|
||||
if #available(iOS 13.0, *) {
|
||||
fpc.surfaceView.layer.cornerCurve = .continuous
|
||||
}
|
||||
#endif
|
||||
|
||||
fpc.delegate = self
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
mainVC.present(fpc, animated: true, completion: nil)
|
||||
|
||||
case .showNavigationController:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.contentInsetAdjustmentBehavior = .never
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showTopPositionedPanel: // For debug
|
||||
let fpc = FloatingPanelController(delegate: self)
|
||||
let contentVC = UIViewController()
|
||||
contentVC.view.backgroundColor = .red
|
||||
fpc.set(contentViewController: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showAdaptivePanel:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
if case let contentVC as ImageViewController = contentVC {
|
||||
let mode: ImageViewController.Mode = (useCase == .showAdaptivePanelWithTableView) ? .withHeaderFooter : .onlyImage
|
||||
let layoutGuide = contentVC.layoutGuideFor(mode: mode)
|
||||
fpc.layout = ImageViewController.PanelLayout(targetGuide: layoutGuide)
|
||||
}
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showAdaptivePanelWithTableView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.track(scrollView: (contentVC as! TableViewControllerForAdaptiveLayout).tableView)
|
||||
fpc.layout = TableViewControllerForAdaptiveLayout.PanelLayout(targetGuide: contentVC.view.makeBoundsLayoutGuide())
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showAdaptivePanelWithCollectionView, .showAdaptivePanelWithCompositionalCollectionView:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
fpc.set(contentViewController: contentVC)
|
||||
if #available(iOS 13, *) {
|
||||
fpc.track(scrollView: (contentVC as! CollectionViewControllerForAdaptiveLayout).collectionView)
|
||||
fpc.layout = CollectionViewControllerForAdaptiveLayout.PanelLayout(targetGuide: contentVC.view.makeBoundsLayoutGuide())
|
||||
}
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showCustomStatePanel:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showCustomBackdrop:
|
||||
class BlurBackdropView: BackdropView {
|
||||
var effectView: UIVisualEffectView!
|
||||
override var alpha: CGFloat {
|
||||
set {
|
||||
effectView.alpha = newValue
|
||||
}
|
||||
get {
|
||||
effectView.alpha
|
||||
}
|
||||
}
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
let effect = UIBlurEffect(style: .prominent)
|
||||
let effectView = UIVisualEffectView(effect: effect)
|
||||
addSubview(effectView)
|
||||
effectView.frame = bounds
|
||||
effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
self.effectView = effectView
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
class CustomBottomLayout: FloatingPanelBottomLayout {
|
||||
override var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 100.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(fractionalInset: 0.1, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
override func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return state == .full ? 0.8 : 0.0
|
||||
}
|
||||
}
|
||||
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.backdropView = BlurBackdropView()
|
||||
fpc.layout = CustomBottomLayout()
|
||||
addMain(panel: fpc)
|
||||
}
|
||||
}
|
||||
|
||||
func setUpSettingsPanel(for mainVC: MainViewController) {
|
||||
guard settingsPanelVC == nil else { return }
|
||||
// Initialize FloatingPanelController
|
||||
settingsPanelVC = FloatingPanelController()
|
||||
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
settingsPanelVC.surfaceView.appearance = appearance
|
||||
|
||||
settingsPanelVC.isRemovalInteractionEnabled = true
|
||||
settingsPanelVC.backdropView.dismissalTapGestureRecognizer.isEnabled = true
|
||||
settingsPanelVC.delegate = self
|
||||
|
||||
let contentVC = mainVC.storyboard?.instantiateViewController(withIdentifier: "SettingsViewController")
|
||||
|
||||
// Set a content view controller
|
||||
settingsPanelVC.set(contentViewController: contentVC)
|
||||
|
||||
// Add FloatingPanel to self.view
|
||||
settingsPanelVC.addPanel(toParent: mainVC, animated: true)
|
||||
}
|
||||
|
||||
private func addMain(panel fpc: FloatingPanelController) {
|
||||
let oldMainPanelVC = mainPanelVC
|
||||
mainPanelVC = fpc
|
||||
if let oldMainPanelVC = oldMainPanelVC {
|
||||
oldMainPanelVC.removePanelFromParent(animated: true, completion: {
|
||||
self.mainPanelVC.addPanel(toParent: self.mainVC, animated: true)
|
||||
})
|
||||
} else {
|
||||
mainPanelVC.addPanel(toParent: mainVC, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func handleSurface(tapGesture: UITapGestureRecognizer) {
|
||||
switch mainPanelVC.state {
|
||||
case .full:
|
||||
mainPanelVC.move(to: .half, animated: true)
|
||||
default:
|
||||
mainPanelVC.move(to: .full, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UseCaseController: FloatingPanelControllerDelegate {
|
||||
func floatingPanel(
|
||||
_ fpc: FloatingPanelController,
|
||||
shouldAllowToScroll scrollView: UIScrollView,
|
||||
in state: FloatingPanelState
|
||||
) -> Bool {
|
||||
return state == .full || state == .half
|
||||
}
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, contentOffsetForPinning trackingScrollView: UIScrollView) -> CGPoint {
|
||||
if useCase == .showNavigationController {
|
||||
// 148.0 is the SafeArea's top value for a navigation bar with a large title.
|
||||
return CGPoint(x: 0.0, y: 0.0 - trackingScrollView.contentInset.top - 148.0)
|
||||
}
|
||||
return CGPoint(x: 0.0, y: 0.0 - trackingScrollView.contentInset.top)
|
||||
}
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
if vc == settingsPanelVC {
|
||||
return IntrinsicPanelLayout()
|
||||
}
|
||||
|
||||
switch useCase {
|
||||
case .showTopPositionedPanel:
|
||||
return TopPositionedPanelLayout()
|
||||
case .showRemovablePanel:
|
||||
return newCollection.verticalSizeClass == .compact ? RemovablePanelLandscapeLayout() : RemovablePanelLayout()
|
||||
case .showIntrinsicView:
|
||||
return IntrinsicPanelLayout()
|
||||
case .showPanelModal:
|
||||
if vc != mainPanelVC && vc != detailPanelVC {
|
||||
return ModalPanelLayout()
|
||||
}
|
||||
fallthrough
|
||||
case .showContentInset:
|
||||
return FloatingPanelBottomLayout()
|
||||
case .showCustomStatePanel:
|
||||
return FloatingPanelLayoutWithCustomState()
|
||||
default:
|
||||
return (newCollection.verticalSizeClass == .compact) ? FloatingPanelBottomLayout() : mainVC
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPanelDidRemove(_ vc: FloatingPanelController) {
|
||||
switch vc {
|
||||
case settingsPanelVC:
|
||||
settingsPanelVC = nil
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UseCaseController: UIGestureRecognizerDelegate {
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if case .showNestedScrollView = useCase {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private extension FloatingPanelController {
|
||||
func ext_trackScrollView(in contentVC: UIViewController) {
|
||||
switch contentVC {
|
||||
case let consoleVC as DebugTextViewController:
|
||||
track(scrollView: consoleVC.textView)
|
||||
|
||||
case let contentVC as DebugTableViewController:
|
||||
let ob = contentVC.tableView.observe(\.isEditing) { [weak self] (tableView, _) in
|
||||
self?.panGestureRecognizer.isEnabled = !tableView.isEditing
|
||||
}
|
||||
contentVC.kvoObservers.append(ob)
|
||||
track(scrollView: contentVC.tableView)
|
||||
|
||||
case let contentVC as NestedScrollViewController:
|
||||
track(scrollView: contentVC.scrollView)
|
||||
|
||||
case let navVC as UINavigationController:
|
||||
if let rootVC = (navVC.topViewController as? MainViewController) {
|
||||
rootVC.loadViewIfNeeded()
|
||||
track(scrollView: rootVC.tableView)
|
||||
}
|
||||
|
||||
case let contentVC as ImageViewController:
|
||||
track(scrollView: contentVC.scrollView)
|
||||
|
||||
case let contentVC as TableViewControllerForAdaptiveLayout:
|
||||
track(scrollView: contentVC.tableView)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
545BA70621BA3214007F7846 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 545BA70521BA3214007F7846 /* AppDelegate.m */; };
|
||||
545BA70921BA3214007F7846 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 545BA70821BA3214007F7846 /* MainViewController.m */; };
|
||||
545BA70C21BA3214007F7846 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545BA70A21BA3214007F7846 /* Main.storyboard */; };
|
||||
545BA70E21BA3217007F7846 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 545BA70D21BA3217007F7846 /* Assets.xcassets */; };
|
||||
545BA71121BA3217007F7846 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545BA70F21BA3217007F7846 /* LaunchScreen.storyboard */; };
|
||||
545BA71421BA3217007F7846 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 545BA71321BA3217007F7846 /* main.m */; };
|
||||
545BA72621BA3BAF007F7846 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 545BA72521BA3BAF007F7846 /* FloatingPanel.framework */; };
|
||||
545BA72721BA3BAF007F7846 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 545BA72521BA3BAF007F7846 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
545BA72821BA3BAF007F7846 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
545BA72721BA3BAF007F7846 /* FloatingPanel.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
545BA70121BA3214007F7846 /* SamplesObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SamplesObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545BA70421BA3214007F7846 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
545BA70521BA3214007F7846 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
545BA70721BA3214007F7846 /* MainViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
|
||||
545BA70821BA3214007F7846 /* MainViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
|
||||
545BA70B21BA3214007F7846 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
545BA70D21BA3217007F7846 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
545BA71021BA3217007F7846 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
545BA71221BA3217007F7846 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545BA71321BA3217007F7846 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
545BA72221BA3867007F7846 /* SamplesObjC-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SamplesObjC-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
545BA72521BA3BAF007F7846 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5D82A6AF28D18443006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
545BA6FE21BA3214007F7846 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545BA72621BA3BAF007F7846 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
545BA6F821BA3214007F7846 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545BA72521BA3BAF007F7846 /* FloatingPanel.framework */,
|
||||
545BA70321BA3214007F7846 /* SamplesObjC */,
|
||||
545BA70221BA3214007F7846 /* Products */,
|
||||
5D82A6AE28D18443006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545BA70221BA3214007F7846 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545BA70121BA3214007F7846 /* SamplesObjC.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545BA70321BA3214007F7846 /* SamplesObjC */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545BA70D21BA3217007F7846 /* Assets.xcassets */,
|
||||
545BA70F21BA3217007F7846 /* LaunchScreen.storyboard */,
|
||||
545BA70A21BA3214007F7846 /* Main.storyboard */,
|
||||
545BA70421BA3214007F7846 /* AppDelegate.h */,
|
||||
545BA70521BA3214007F7846 /* AppDelegate.m */,
|
||||
545BA70721BA3214007F7846 /* MainViewController.h */,
|
||||
545BA70821BA3214007F7846 /* MainViewController.m */,
|
||||
545BA71221BA3217007F7846 /* Info.plist */,
|
||||
545BA71321BA3217007F7846 /* main.m */,
|
||||
545BA72221BA3867007F7846 /* SamplesObjC-Bridging-Header.h */,
|
||||
);
|
||||
path = SamplesObjC;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6AE28D18443006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6AF28D18443006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
545BA70021BA3214007F7846 /* SamplesObjC */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545BA71721BA3217007F7846 /* Build configuration list for PBXNativeTarget "SamplesObjC" */;
|
||||
buildPhases = (
|
||||
545BA6FD21BA3214007F7846 /* Sources */,
|
||||
545BA6FE21BA3214007F7846 /* Frameworks */,
|
||||
545BA6FF21BA3214007F7846 /* Resources */,
|
||||
545BA72821BA3BAF007F7846 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = SamplesObjC;
|
||||
productName = SamplesObjC;
|
||||
productReference = 545BA70121BA3214007F7846 /* SamplesObjC.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
545BA6F921BA3214007F7846 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "Shin Yamamoto";
|
||||
TargetAttributes = {
|
||||
545BA70021BA3214007F7846 = {
|
||||
CreatedOnToolsVersion = 10.1;
|
||||
LastSwiftMigration = 1010;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 545BA6FC21BA3214007F7846 /* Build configuration list for PBXProject "SamplesObjC" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 545BA6F821BA3214007F7846;
|
||||
productRefGroup = 545BA70221BA3214007F7846 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
545BA70021BA3214007F7846 /* SamplesObjC */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
545BA6FF21BA3214007F7846 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545BA71121BA3217007F7846 /* LaunchScreen.storyboard in Resources */,
|
||||
545BA70E21BA3217007F7846 /* Assets.xcassets in Resources */,
|
||||
545BA70C21BA3214007F7846 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
545BA6FD21BA3214007F7846 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545BA70921BA3214007F7846 /* MainViewController.m in Sources */,
|
||||
545BA71421BA3217007F7846 /* main.m in Sources */,
|
||||
545BA70621BA3214007F7846 /* AppDelegate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
545BA70A21BA3214007F7846 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
545BA70B21BA3214007F7846 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545BA70F21BA3217007F7846 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
545BA71021BA3217007F7846 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
545BA71521BA3217007F7846 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545BA71621BA3217007F7846 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545BA71821BA3217007F7846 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = NO;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
INFOPLIST_FILE = SamplesObjC/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.SamplesObjC;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "SamplesObjC/SamplesObjC-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545BA71921BA3217007F7846 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = NO;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
INFOPLIST_FILE = SamplesObjC/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.SamplesObjC;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "SamplesObjC/SamplesObjC-Bridging-Header.h";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
545BA6FC21BA3214007F7846 /* Build configuration list for PBXProject "SamplesObjC" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545BA71521BA3217007F7846 /* Debug */,
|
||||
545BA71621BA3217007F7846 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545BA71721BA3217007F7846 /* Build configuration list for PBXNativeTarget "SamplesObjC" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545BA71821BA3217007F7846 /* Debug */,
|
||||
545BA71921BA3217007F7846 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 545BA6F921BA3214007F7846 /* Project object */;
|
||||
}
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:FloatingModalController.xcodeproj">
|
||||
location = "self:SamplesObjC.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545BA70021BA3214007F7846"
|
||||
BuildableName = "SamplesObjC.app"
|
||||
BlueprintName = "SamplesObjC"
|
||||
ReferencedContainer = "container:SamplesObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545BA70021BA3214007F7846"
|
||||
BuildableName = "SamplesObjC.app"
|
||||
BlueprintName = "SamplesObjC"
|
||||
ReferencedContainer = "container:SamplesObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545BA70021BA3214007F7846"
|
||||
BuildableName = "SamplesObjC.app"
|
||||
BlueprintName = "SamplesObjC"
|
||||
ReferencedContainer = "container:SamplesObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545BA70021BA3214007F7846"
|
||||
BuildableName = "SamplesObjC.app"
|
||||
BlueprintName = "SamplesObjC"
|
||||
ReferencedContainer = "container:SamplesObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow* window;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface AppDelegate ()
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
@end
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="MainViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@import FloatingPanel;
|
||||
|
||||
@interface MainViewController : UIViewController
|
||||
@end
|
||||
|
||||
@interface MyFloatingPanelLayout : NSObject <FloatingPanelLayout>
|
||||
@end
|
||||
|
||||
@interface MyFloatingPanelBehavior : NSObject <FloatingPanelBehavior>
|
||||
@end
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
#import "MainViewController.h"
|
||||
@import FloatingPanel;
|
||||
|
||||
// Defining a custom FloatingPanelState
|
||||
@interface FloatingPanelState(Extended)
|
||||
+ (FloatingPanelState *)LastQuart;
|
||||
@end
|
||||
|
||||
@implementation FloatingPanelState(Extended)
|
||||
static FloatingPanelState *_lastQuart;
|
||||
+ (FloatingPanelState *)LastQuart {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_lastQuart = [[FloatingPanelState alloc] initWithRawValue:@"lastquart" order:750];
|
||||
});
|
||||
return _lastQuart;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface MainViewController()<FloatingPanelControllerDelegate>
|
||||
@end
|
||||
|
||||
@implementation MainViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
FloatingPanelController *fpc = [[FloatingPanelController alloc] init];
|
||||
[fpc setContentViewController:nil];
|
||||
[fpc setDelegate:self];
|
||||
|
||||
[fpc setLayout: [MyFloatingPanelLayout new]];
|
||||
[fpc setBehavior:[MyFloatingPanelBehavior new]];
|
||||
[fpc setRemovalInteractionEnabled:NO];
|
||||
|
||||
[fpc addPanelToParent:self at:self.view.subviews.count animated:NO completion:nil];
|
||||
[fpc moveToState:FloatingPanelState.Tip animated:true completion:nil];
|
||||
|
||||
[self updateAppearance: fpc];
|
||||
}
|
||||
|
||||
- (id<FloatingPanelLayout>)floatingPanel:(FloatingPanelController *)vc layoutFor:(UITraitCollection *)newCollection {
|
||||
FloatingPanelBottomLayout *layout = [FloatingPanelBottomLayout new];
|
||||
return layout;
|
||||
}
|
||||
|
||||
- (void)updateAppearance: (FloatingPanelController*)fpc
|
||||
{
|
||||
FloatingPanelSurfaceAppearance *appearance = [[FloatingPanelSurfaceAppearance alloc] init];
|
||||
appearance.backgroundColor = [UIColor clearColor];
|
||||
appearance.cornerRadius = 23.0;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
fpc.surfaceView.containerView.layer.cornerCurve = kCACornerCurveContinuous;
|
||||
}
|
||||
FloatingPanelSurfaceAppearanceShadow *shadow = [[FloatingPanelSurfaceAppearanceShadow alloc] init];
|
||||
shadow.color = [UIColor redColor];
|
||||
shadow.radius = 10.0;
|
||||
shadow.spread = 10.0;
|
||||
FloatingPanelSurfaceAppearanceShadow *shadow2 = [[FloatingPanelSurfaceAppearanceShadow alloc] init];
|
||||
shadow2.color = [UIColor blueColor];
|
||||
shadow2.radius = 10.0;
|
||||
shadow2.spread = 10.0;
|
||||
|
||||
appearance.shadows = @[shadow, shadow2];
|
||||
fpc.surfaceView.appearance = appearance;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MyFloatingPanelLayout
|
||||
- (FloatingPanelState *)initialState {
|
||||
return FloatingPanelState.Half;
|
||||
}
|
||||
- (NSDictionary<FloatingPanelState *, id<FloatingPanelLayoutAnchoring>> *)anchors {
|
||||
return @{
|
||||
FloatingPanelState.LastQuart: [[FloatingPanelLayoutAnchor alloc] initWithFractionalInset:0.25
|
||||
edge:FloatingPanelReferenceEdgeTop
|
||||
referenceGuide:FloatingPanelLayoutReferenceGuideSafeArea],
|
||||
FloatingPanelState.Half: [[FloatingPanelLayoutAnchor alloc] initWithFractionalInset:0.5
|
||||
edge:FloatingPanelReferenceEdgeTop
|
||||
referenceGuide:FloatingPanelLayoutReferenceGuideSafeArea],
|
||||
FloatingPanelState.Tip: [[FloatingPanelLayoutAnchor alloc] initWithAbsoluteInset:44.0
|
||||
edge:FloatingPanelReferenceEdgeBottom
|
||||
referenceGuide:FloatingPanelLayoutReferenceGuideSafeArea],
|
||||
};
|
||||
}
|
||||
|
||||
- (enum FloatingPanelPosition)position {
|
||||
return FloatingPanelPositionBottom;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation MyFloatingPanelBehavior
|
||||
@end
|
||||
@@ -0,0 +1,3 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,14 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5433F24B21717EA300BDAA5D /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5433F24A21717EA300BDAA5D /* FloatingPanel.framework */; };
|
||||
5433F24C21717EA300BDAA5D /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5433F24A21717EA300BDAA5D /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
548DF95421705BE00041922A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 548DF95321705BE00041922A /* AppDelegate.swift */; };
|
||||
548DF95621705BE00041922A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 548DF95521705BE00041922A /* ViewController.swift */; };
|
||||
548DF95621705BE00041922A /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 548DF95521705BE00041922A /* MainViewController.swift */; };
|
||||
548DF95921705BE00041922A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 548DF95721705BE00041922A /* Main.storyboard */; };
|
||||
548DF95B21705BE10041922A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 548DF95A21705BE10041922A /* Assets.xcassets */; };
|
||||
548DF95E21705BE10041922A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 548DF95C21705BE10041922A /* LaunchScreen.storyboard */; };
|
||||
549D23CF233C77CF008EF4D7 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */; };
|
||||
549D23D0233C77CF008EF4D7 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
5D82A6AA28D18432006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6A928D1842B006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -23,7 +24,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
5433F24C21717EA300BDAA5D /* FloatingPanel.framework in Embed Frameworks */,
|
||||
549D23D0233C77CF008EF4D7 /* FloatingPanel.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -31,14 +32,15 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5433F24A21717EA300BDAA5D /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
548DF95021705BE00041922A /* Stocks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stocks.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
548DF95321705BE00041922A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
548DF95521705BE00041922A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
548DF95521705BE00041922A /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
548DF95821705BE00041922A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
548DF95A21705BE10041922A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
548DF95D21705BE10041922A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
548DF95F21705BE10041922A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5D82A6A928D1842B006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -46,7 +48,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5433F24B21717EA300BDAA5D /* FloatingPanel.framework in Frameworks */,
|
||||
5D82A6AA28D18432006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
549D23CF233C77CF008EF4D7 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -56,9 +59,10 @@
|
||||
548DF94721705BE00041922A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5433F24A21717EA300BDAA5D /* FloatingPanel.framework */,
|
||||
549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */,
|
||||
548DF95221705BE00041922A /* Stocks */,
|
||||
548DF95121705BE00041922A /* Products */,
|
||||
5D82A6A828D1842A006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -73,16 +77,24 @@
|
||||
548DF95221705BE00041922A /* Stocks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
548DF95321705BE00041922A /* AppDelegate.swift */,
|
||||
548DF95521705BE00041922A /* ViewController.swift */,
|
||||
548DF95721705BE00041922A /* Main.storyboard */,
|
||||
548DF95A21705BE10041922A /* Assets.xcassets */,
|
||||
548DF95C21705BE10041922A /* LaunchScreen.storyboard */,
|
||||
548DF95721705BE00041922A /* Main.storyboard */,
|
||||
548DF95321705BE00041922A /* AppDelegate.swift */,
|
||||
548DF95521705BE00041922A /* MainViewController.swift */,
|
||||
548DF95F21705BE10041922A /* Info.plist */,
|
||||
);
|
||||
path = Stocks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6A828D1842A006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6A928D1842B006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -111,7 +123,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1000;
|
||||
LastUpgradeCheck = 1000;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = scenee;
|
||||
TargetAttributes = {
|
||||
548DF94F21705BE00041922A = {
|
||||
@@ -155,7 +167,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
548DF95621705BE00041922A /* ViewController.swift in Sources */,
|
||||
548DF95621705BE00041922A /* MainViewController.swift in Sources */,
|
||||
548DF95421705BE00041922A /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -208,6 +220,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -269,6 +282,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -303,16 +317,20 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Stocks/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.Stocks;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Stocks;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -322,16 +340,20 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Stocks/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.Stocks;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Stocks;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,8 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -38,8 +36,8 @@
|
||||
ReferencedContainer = "container:Stocks.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -61,8 +59,6 @@
|
||||
ReferencedContainer = "container:Stocks.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Stocks
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/10/12.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina5_9" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Stocks" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="BYZ-38-t0r" customClass="MainViewController" customModule="Stocks" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Uop-sw-I6p">
|
||||
<rect key="frame" x="0.0" y="109" width="375" height="624.66666666666663"/>
|
||||
<rect key="frame" x="0.0" y="65" width="600" height="490.5"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" placeholderIntrinsicWidth="375" placeholderIntrinsicHeight="625" image="stocks_list" translatesAutoresizingMaskIntoConstraints="NO" id="XJR-iK-fem">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="625"/>
|
||||
@@ -34,10 +30,10 @@
|
||||
</constraints>
|
||||
</scrollView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dFl-81-6ok">
|
||||
<rect key="frame" x="0.0" y="733.66666666666663" width="375" height="78.333333333333371"/>
|
||||
<rect key="frame" x="0.0" y="555.5" width="600" height="44.5"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="yahoo_bottom_bar" translatesAutoresizingMaskIntoConstraints="NO" id="NKr-gS-mpx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44.333333333333336"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="44.5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44.5" id="B5t-ZF-qUj"/>
|
||||
@@ -52,18 +48,17 @@
|
||||
<constraint firstItem="NKr-gS-mpx" firstAttribute="leading" secondItem="dFl-81-6ok" secondAttribute="leading" id="T2r-kY-JYy"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" axis="vertical" alignment="top" spacing="-8" translatesAutoresizingMaskIntoConstraints="NO" id="f7r-Al-pIN">
|
||||
<rect key="frame" x="16" y="44.000000000000014" width="153.33333333333334" height="56.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="-8" translatesAutoresizingMaskIntoConstraints="NO" id="f7r-Al-pIN">
|
||||
<rect key="frame" x="16" y="0.0" width="153.5" height="57"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="STOCKS" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PCG-Wl-fXa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="111.66666666666667" height="32.333333333333336"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="111" height="32.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="27"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="OCTOBER 5" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XmK-pu-9g4">
|
||||
<rect key="frame" x="0.0" y="24.333333333333332" width="153.33333333333334" height="32.333333333333343"/>
|
||||
<rect key="frame" x="0.0" y="24.5" width="153.5" height="32.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="27"/>
|
||||
<color key="textColor" red="0.55308091640472412" green="0.55657511949539185" blue="0.57255202531814575" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -71,18 +66,20 @@
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" red="0.11764924973249435" green="0.11764311045408249" blue="0.11764728277921677" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
<constraints>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="dFl-81-6ok" secondAttribute="trailing" id="20i-yz-AaQ"/>
|
||||
<constraint firstItem="Uop-sw-I6p" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="44w-r8-vYl"/>
|
||||
<constraint firstItem="f7r-Al-pIN" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="4Bq-Km-eET"/>
|
||||
<constraint firstItem="Uop-sw-I6p" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="65" id="CXL-Dk-8MM"/>
|
||||
<constraint firstItem="Uop-sw-I6p" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="CsO-WF-T8L"/>
|
||||
<constraint firstItem="dFl-81-6ok" firstAttribute="top" secondItem="Uop-sw-I6p" secondAttribute="bottom" id="Cz0-dW-r9H"/>
|
||||
<constraint firstAttribute="bottom" secondItem="dFl-81-6ok" secondAttribute="bottom" id="KGl-8W-5ja"/>
|
||||
<constraint firstItem="f7r-Al-pIN" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="1.4210854715202004e-14" id="Qvt-vQ-PpT"/>
|
||||
<constraint firstItem="dFl-81-6ok" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="nlX-Ab-1aI"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="NKr-gS-mpx" secondAttribute="bottom" id="yeu-NH-Pmp"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="bottomToolView" destination="dFl-81-6ok" id="NXn-af-lFv"/>
|
||||
@@ -121,6 +118,7 @@
|
||||
</constraints>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="INo-op-FLO"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="h7M-7T-4k4" secondAttribute="bottom" id="2b8-Wo-tm0"/>
|
||||
@@ -128,7 +126,6 @@
|
||||
<constraint firstItem="h7M-7T-4k4" firstAttribute="trailing" secondItem="INo-op-FLO" secondAttribute="trailing" id="WTc-1l-3Ha"/>
|
||||
<constraint firstItem="h7M-7T-4k4" firstAttribute="leading" secondItem="INo-op-FLO" secondAttribute="leading" id="na8-TO-WiG"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="INo-op-FLO"/>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="600"/>
|
||||
<connections>
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
class MainViewController: UIViewController, FloatingPanelControllerDelegate {
|
||||
@IBOutlet var topBannerView: UIImageView!
|
||||
@IBOutlet weak var labelStackView: UIStackView!
|
||||
@IBOutlet weak var bottomToolView: UIView!
|
||||
|
||||
var fpc: FloatingPanelController!
|
||||
var newsVC: NewsViewController!
|
||||
|
||||
var initialColor: UIColor = .black
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
initialColor = view.backgroundColor!
|
||||
// Initialize FloatingPanelController
|
||||
fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
fpc.behavior = FloatingPanelStocksBehavior()
|
||||
|
||||
// Initialize FloatingPanelController and add the view
|
||||
fpc.surfaceView.backgroundColor = UIColor(displayP3Red: 30.0/255.0, green: 30.0/255.0, blue: 30.0/255.0, alpha: 1.0)
|
||||
fpc.surfaceView.appearance.cornerRadius = 24.0
|
||||
fpc.surfaceView.appearance.shadows = []
|
||||
fpc.surfaceView.appearance.borderWidth = 1.0 / traitCollection.displayScale
|
||||
fpc.surfaceView.appearance.borderColor = UIColor.black.withAlphaComponent(0.2)
|
||||
|
||||
newsVC = storyboard?.instantiateViewController(withIdentifier: "News") as? NewsViewController
|
||||
|
||||
// Set a content view controller
|
||||
fpc.set(contentViewController: newsVC)
|
||||
fpc.track(scrollView: newsVC.scrollView)
|
||||
|
||||
fpc.addPanel(toParent: self, at: view.subviews.firstIndex(of: bottomToolView) ?? -1 , animated: false)
|
||||
|
||||
topBannerView.frame = .zero
|
||||
topBannerView.alpha = 0.0
|
||||
view.addSubview(topBannerView)
|
||||
topBannerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
topBannerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0),
|
||||
topBannerView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0.0),
|
||||
])
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return .lightContent
|
||||
}
|
||||
|
||||
// MARK: FloatingPanelControllerDelegate
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
return FloatingPanelStocksLayout()
|
||||
}
|
||||
|
||||
func floatingPanelDidMove(_ vc: FloatingPanelController) {
|
||||
if vc.isAttracting == false {
|
||||
let loc = vc.surfaceLocation
|
||||
let minY = vc.surfaceLocation(for: .full).y
|
||||
let maxY = vc.surfaceLocation(for: .tip).y
|
||||
vc.surfaceLocation = CGPoint(x: loc.x, y: min(max(loc.y, minY), maxY))
|
||||
}
|
||||
|
||||
if vc.surfaceLocation.y <= vc.surfaceLocation(for: .full).y + 100 {
|
||||
showStockTickerBanner()
|
||||
} else {
|
||||
hideStockTickerBanner()
|
||||
}
|
||||
}
|
||||
|
||||
private func showStockTickerBanner() {
|
||||
// Present top bar with dissolve animation
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.topBannerView.alpha = 1.0
|
||||
self.labelStackView.alpha = 0.0
|
||||
self.view.backgroundColor = .black
|
||||
}
|
||||
}
|
||||
|
||||
private func hideStockTickerBanner() {
|
||||
// Dismiss top bar with dissolve animation
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.topBannerView.alpha = 0.0
|
||||
self.labelStackView.alpha = 1.0
|
||||
self.view.backgroundColor = .black
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NewsViewController: UIViewController {
|
||||
@IBOutlet weak var scrollView: UIScrollView!
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FloatingPanelLayout
|
||||
|
||||
class FloatingPanelStocksLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .tip
|
||||
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 56.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
/* Visible + ToolView */
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 85.0 + 44.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - FloatingPanelBehavior
|
||||
|
||||
class FloatingPanelStocksBehavior: FloatingPanelBehavior {
|
||||
let springDecelerationRate: CGFloat = UIScrollView.DecelerationRate.fast.rawValue
|
||||
let springResponseTime: CGFloat = 0.25
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// Stocks
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/10/12.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
class ViewController: UIViewController, FloatingPanelControllerDelegate {
|
||||
@IBOutlet var topBannerView: UIImageView!
|
||||
@IBOutlet weak var labelStackView: UIStackView!
|
||||
@IBOutlet weak var bottomToolView: UIView!
|
||||
|
||||
var fpc: FloatingPanelController!
|
||||
var newsVC: NewsViewController!
|
||||
|
||||
var initialColor: UIColor = .black
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
initialColor = view.backgroundColor!
|
||||
// Initialize FloatingPanelController
|
||||
fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
|
||||
// Initialize FloatingPanelController and add the view
|
||||
fpc.surfaceView.backgroundColor = UIColor(displayP3Red: 30.0/255.0, green: 30.0/255.0, blue: 30.0/255.0, alpha: 1.0)
|
||||
fpc.surfaceView.cornerRadius = 24.0
|
||||
fpc.surfaceView.shadowHidden = true
|
||||
fpc.surfaceView.borderWidth = 1.0 / traitCollection.displayScale
|
||||
fpc.surfaceView.borderColor = UIColor.black.withAlphaComponent(0.2)
|
||||
|
||||
newsVC = storyboard?.instantiateViewController(withIdentifier: "News") as? NewsViewController
|
||||
|
||||
// Add a content view controller
|
||||
fpc.show(newsVC, sender: self)
|
||||
fpc.track(scrollView: newsVC.scrollView)
|
||||
|
||||
fpc.add(toParent: self, belowView: bottomToolView, animated: false)
|
||||
|
||||
topBannerView.frame = .zero
|
||||
topBannerView.alpha = 0.0
|
||||
view.addSubview(topBannerView)
|
||||
topBannerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
topBannerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0),
|
||||
topBannerView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0.0),
|
||||
])
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return .lightContent
|
||||
}
|
||||
|
||||
// MARK: FloatingPanelControllerDelegate
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? {
|
||||
return FloatingPanelStocksLayout()
|
||||
}
|
||||
|
||||
func floatingPanel(_ vc: FloatingPanelController, behaviorFor newCollection: UITraitCollection) -> FloatingPanelBehavior? {
|
||||
return FloatingPanelStocksBehavior()
|
||||
}
|
||||
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
|
||||
if vc.position == .full {
|
||||
// Dimiss top bar with dissolve animation
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.topBannerView.alpha = 0.0
|
||||
self.labelStackView.alpha = 1.0
|
||||
self.view.backgroundColor = self.initialColor
|
||||
}
|
||||
}
|
||||
}
|
||||
func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition) {
|
||||
if targetPosition == .full {
|
||||
// Present top bar with dissolve animation
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.topBannerView.alpha = 1.0
|
||||
self.labelStackView.alpha = 0.0
|
||||
self.view.backgroundColor = .black
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NewsViewController: UIViewController {
|
||||
@IBOutlet weak var scrollView: UIScrollView!
|
||||
}
|
||||
|
||||
|
||||
// MARK: My custom layout
|
||||
|
||||
class FloatingPanelStocksLayout: FloatingPanelLayout {
|
||||
public var supportedPositions: [FloatingPanelPosition] {
|
||||
return [.full, .half, .tip]
|
||||
}
|
||||
|
||||
public var initialPosition: FloatingPanelPosition {
|
||||
return .tip
|
||||
}
|
||||
|
||||
public func insetFor(position: FloatingPanelPosition) -> CGFloat? {
|
||||
switch position {
|
||||
case .full: return 56.0
|
||||
case .half: return 262.0
|
||||
case .tip: return 85.0 + 44.0 // Visible + ToolView
|
||||
}
|
||||
}
|
||||
|
||||
public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
return [
|
||||
surfaceView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0.0),
|
||||
surfaceView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: 0.0),
|
||||
]
|
||||
}
|
||||
|
||||
var backdropAlpha: CGFloat = 0.0
|
||||
}
|
||||
|
||||
// MARK: My custom behavior
|
||||
|
||||
class FloatingPanelStocksBehavior: FloatingPanelBehavior {
|
||||
var velocityThreshold: CGFloat {
|
||||
return 15.0
|
||||
}
|
||||
|
||||
func interactionAnimator(to targetPosition: FloatingPanelPosition, with velocity: CGVector) -> UIViewPropertyAnimator {
|
||||
let damping = self.damping(with: velocity)
|
||||
let springTiming = UISpringTimingParameters(dampingRatio: damping,
|
||||
initialVelocity: velocity)
|
||||
let duration = getDuration(with: velocity)
|
||||
return UIViewPropertyAnimator(duration: duration, timingParameters: springTiming)
|
||||
}
|
||||
|
||||
private func getDuration(with velocity: CGVector) -> TimeInterval {
|
||||
let dy = abs(velocity.dy)
|
||||
switch dy {
|
||||
case ..<1.0:
|
||||
return 0.5
|
||||
case 1.0..<velocityThreshold:
|
||||
let a = ((dy - 1.0) / (velocityThreshold - 1.0))
|
||||
return TimeInterval(0.5 - (0.25 * a))
|
||||
case velocityThreshold...:
|
||||
return 0.25
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
private func damping(with velocity: CGVector) -> CGFloat {
|
||||
switch velocity.dy {
|
||||
case ...(-velocityThreshold):
|
||||
return 0.7
|
||||
case velocityThreshold...:
|
||||
return 0.7
|
||||
default:
|
||||
return 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-12
@@ -1,24 +1,22 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "FloatingPanel"
|
||||
s.version = "0.9"
|
||||
s.summary = "FloatingPanel is a simple and easy-to-use UI component of a floating panel interface"
|
||||
s.version = "2.8.6"
|
||||
s.summary = "FloatingPanel is a clean and easy-to-use UI component of a floating panel interface."
|
||||
s.description = <<-DESC
|
||||
FloatingPanel is a simple and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app.
|
||||
FloatingPanel is a clean and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app.
|
||||
The new interface displays the related contents and utilities in parallel as a user wants.
|
||||
DESC
|
||||
s.homepage = "https://github.com/SCENEE/FloatingPanel"
|
||||
# s.screenshots = ""
|
||||
s.homepage = "https://github.com/scenee/FloatingPanel"
|
||||
s.author = "Shin Yamamoto"
|
||||
s.social_media_url = "https://twitter.com/scenee"
|
||||
|
||||
s.platform = :ios, "10.0"
|
||||
s.source = { :git => "https://github.com/SCENEE/FloatingPanel.git", :tag => "v#{s.version}" }
|
||||
s.source_files = "Framework/Sources/*.swift"
|
||||
s.swift_version = "4.2"
|
||||
s.pod_target_xcconfig = { 'SWIFT_WHOLE_MODULE_OPTIMIZATION' => 'YES', 'APPLICATION_EXTENSION_API_ONLY' => 'YES' }
|
||||
s.platform = :ios, "11.0"
|
||||
s.source = { :git => "https://github.com/scenee/FloatingPanel.git", :tag => s.version.to_s }
|
||||
s.source_files = "Sources/*.swift"
|
||||
s.swift_version = '5.0'
|
||||
|
||||
s.framework = "UIKit"
|
||||
|
||||
s.author = { "Shin Yamamoto" => "shin@scenee.com" }
|
||||
s.license = { :type => "MIT", :file => "LICENSE" }
|
||||
s.social_media_url = "https://twitter.com/scenee"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,712 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
542753C622C49A6E00D17955 /* LayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542753C522C49A6E00D17955 /* LayoutTests.swift */; };
|
||||
54352E9621A51A2500CBCA08 /* Transitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54352E9521A51A2500CBCA08 /* Transitioning.swift */; };
|
||||
54352E9821A521CA00CBCA08 /* PassthroughView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54352E9721A521CA00CBCA08 /* PassthroughView.swift */; };
|
||||
5450EEE421646DF500135936 /* Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5450EEE321646DF500135936 /* Behavior.swift */; };
|
||||
545DB9CB2151169500CA77B8 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 545DB9C12151169500CA77B8 /* FloatingPanel.framework */; };
|
||||
545DB9D02151169500CA77B8 /* ControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9CF2151169500CA77B8 /* ControllerTests.swift */; };
|
||||
545DB9D22151169500CA77B8 /* FloatingPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = 545DB9C42151169500CA77B8 /* FloatingPanel.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
545DB9E021511AC100CA77B8 /* Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9DF21511AC100CA77B8 /* Controller.swift */; };
|
||||
545DBA2B2152383100CA77B8 /* GrabberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DBA2A2152383100CA77B8 /* GrabberView.swift */; };
|
||||
546055BF2333C4740069F400 /* TestSupports.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542753C722C49A8F00D17955 /* TestSupports.swift */; };
|
||||
5469F4AE24B30D7E00537F8A /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4AD24B30D7E00537F8A /* State.swift */; };
|
||||
5469F4B024B30E1500537F8A /* LayoutAnchoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4AF24B30E1500537F8A /* LayoutAnchoring.swift */; };
|
||||
5469F4B224B30F1100537F8A /* Position.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4B124B30F1100537F8A /* Position.swift */; };
|
||||
5469F4B424B30F3500537F8A /* LayoutProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4B324B30F3500537F8A /* LayoutProperties.swift */; };
|
||||
547F7A9C2A6E946000303905 /* GestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 547F7A9B2A6E946000303905 /* GestureTests.swift */; };
|
||||
549C371F2361E15E007D8058 /* ExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549C371E2361E15D007D8058 /* ExtensionTests.swift */; };
|
||||
549E944522CF295D0050AECF /* StateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E944422CF295D0050AECF /* StateTests.swift */; };
|
||||
54A6B6B122968B530077F348 /* CoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A6B6B022968B530077F348 /* CoreTests.swift */; };
|
||||
54A6B6B82296A8520077F348 /* SurfaceViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A6B6B72296A8520077F348 /* SurfaceViewTests.swift */; };
|
||||
54ABD7AF216CCFF7002E6C13 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54ABD7AE216CCFF7002E6C13 /* Logging.swift */; };
|
||||
54CDC5D3215B6D5A007D205C /* SurfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D2215B6D5A007D205C /* SurfaceView.swift */; };
|
||||
54CDC5D5215B6D8D007D205C /* BackdropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D4215B6D8D007D205C /* BackdropView.swift */; };
|
||||
54CFBFC3215CD045006B5735 /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CFBFC2215CD045006B5735 /* Layout.swift */; };
|
||||
54CFBFC5215CD09C006B5735 /* Core.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CFBFC4215CD09C006B5735 /* Core.swift */; };
|
||||
54DBA3DC262E938500D75969 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54DBA3DB262E938500D75969 /* Extensions.swift */; };
|
||||
54E3992727141F5100A8F9ED /* FloatingPanel.docc in Sources */ = {isa = PBXBuildFile; fileRef = 54E3992627141F5100A8F9ED /* FloatingPanel.docc */; };
|
||||
5D82A6B528D18464006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6B428D18461006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
545DB9CC2151169500CA77B8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 545DB9B82151169500CA77B8 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 545DB9C02151169500CA77B8;
|
||||
remoteInfo = FloatingModalController;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
542753C522C49A6E00D17955 /* LayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutTests.swift; sourceTree = "<group>"; };
|
||||
542753C722C49A8F00D17955 /* TestSupports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSupports.swift; sourceTree = "<group>"; };
|
||||
54352E9521A51A2500CBCA08 /* Transitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transitioning.swift; sourceTree = "<group>"; };
|
||||
54352E9721A521CA00CBCA08 /* PassthroughView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassthroughView.swift; sourceTree = "<group>"; };
|
||||
5450EEE321646DF500135936 /* Behavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Behavior.swift; sourceTree = "<group>"; };
|
||||
545DB9C12151169500CA77B8 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DB9C42151169500CA77B8 /* FloatingPanel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FloatingPanel.h; sourceTree = "<group>"; };
|
||||
545DB9C52151169500CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FloatingPanelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DB9CF2151169500CA77B8 /* ControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControllerTests.swift; sourceTree = "<group>"; };
|
||||
545DB9D12151169500CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DB9DF21511AC100CA77B8 /* Controller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = "<group>"; };
|
||||
545DBA2A2152383100CA77B8 /* GrabberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrabberView.swift; sourceTree = "<group>"; };
|
||||
5469F4AD24B30D7E00537F8A /* State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = "<group>"; };
|
||||
5469F4AF24B30E1500537F8A /* LayoutAnchoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutAnchoring.swift; sourceTree = "<group>"; };
|
||||
5469F4B124B30F1100537F8A /* Position.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Position.swift; sourceTree = "<group>"; };
|
||||
5469F4B324B30F3500537F8A /* LayoutProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutProperties.swift; sourceTree = "<group>"; };
|
||||
547F7A9B2A6E946000303905 /* GestureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureTests.swift; sourceTree = "<group>"; };
|
||||
549C371E2361E15D007D8058 /* ExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionTests.swift; sourceTree = "<group>"; };
|
||||
549E944422CF295D0050AECF /* StateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateTests.swift; sourceTree = "<group>"; };
|
||||
54A6B6B022968B530077F348 /* CoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreTests.swift; sourceTree = "<group>"; };
|
||||
54A6B6B72296A8520077F348 /* SurfaceViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceViewTests.swift; sourceTree = "<group>"; };
|
||||
54ABD7AE216CCFF7002E6C13 /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
||||
54CDC5D2215B6D5A007D205C /* SurfaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceView.swift; sourceTree = "<group>"; };
|
||||
54CDC5D4215B6D8D007D205C /* BackdropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackdropView.swift; sourceTree = "<group>"; };
|
||||
54CFBFC2215CD045006B5735 /* Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layout.swift; sourceTree = "<group>"; };
|
||||
54CFBFC4215CD09C006B5735 /* Core.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core.swift; sourceTree = "<group>"; };
|
||||
54DBA3DB262E938500D75969 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
|
||||
54E3992627141F5100A8F9ED /* FloatingPanel.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = FloatingPanel.docc; sourceTree = "<group>"; };
|
||||
5D82A6B428D18461006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = DEVELOPER_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
545DB9BE2151169500CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D82A6B528D18464006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9C72151169500CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DB9CB2151169500CA77B8 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
545DB9B72151169500CA77B8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9C32151169500CA77B8 /* Sources */,
|
||||
545DB9CE2151169500CA77B8 /* Tests */,
|
||||
545DB9C22151169500CA77B8 /* Products */,
|
||||
5D82A6B328D18460006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9C22151169500CA77B8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9C12151169500CA77B8 /* FloatingPanel.framework */,
|
||||
545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9C32151169500CA77B8 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9DF21511AC100CA77B8 /* Controller.swift */,
|
||||
5469F4AD24B30D7E00537F8A /* State.swift */,
|
||||
5469F4B124B30F1100537F8A /* Position.swift */,
|
||||
54CFBFC4215CD09C006B5735 /* Core.swift */,
|
||||
54CFBFC2215CD045006B5735 /* Layout.swift */,
|
||||
5469F4B324B30F3500537F8A /* LayoutProperties.swift */,
|
||||
5469F4AF24B30E1500537F8A /* LayoutAnchoring.swift */,
|
||||
5450EEE321646DF500135936 /* Behavior.swift */,
|
||||
54352E9721A521CA00CBCA08 /* PassthroughView.swift */,
|
||||
54CDC5D2215B6D5A007D205C /* SurfaceView.swift */,
|
||||
54CDC5D4215B6D8D007D205C /* BackdropView.swift */,
|
||||
545DBA2A2152383100CA77B8 /* GrabberView.swift */,
|
||||
54352E9521A51A2500CBCA08 /* Transitioning.swift */,
|
||||
54DBA3DB262E938500D75969 /* Extensions.swift */,
|
||||
54ABD7AE216CCFF7002E6C13 /* Logging.swift */,
|
||||
545DB9C42151169500CA77B8 /* FloatingPanel.h */,
|
||||
545DB9C52151169500CA77B8 /* Info.plist */,
|
||||
54E3992627141F5100A8F9ED /* FloatingPanel.docc */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9CE2151169500CA77B8 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54A6B6B022968B530077F348 /* CoreTests.swift */,
|
||||
545DB9CF2151169500CA77B8 /* ControllerTests.swift */,
|
||||
547F7A9B2A6E946000303905 /* GestureTests.swift */,
|
||||
542753C522C49A6E00D17955 /* LayoutTests.swift */,
|
||||
54A6B6B72296A8520077F348 /* SurfaceViewTests.swift */,
|
||||
549E944422CF295D0050AECF /* StateTests.swift */,
|
||||
549C371E2361E15D007D8058 /* ExtensionTests.swift */,
|
||||
542753C722C49A8F00D17955 /* TestSupports.swift */,
|
||||
545DB9D12151169500CA77B8 /* Info.plist */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6B328D18460006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6B428D18461006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
545DB9BC2151169500CA77B8 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DB9D22151169500CA77B8 /* FloatingPanel.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
545DB9C02151169500CA77B8 /* FloatingPanel */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DB9D52151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanel" */;
|
||||
buildPhases = (
|
||||
545DB9BC2151169500CA77B8 /* Headers */,
|
||||
545DB9BD2151169500CA77B8 /* Sources */,
|
||||
545DB9BE2151169500CA77B8 /* Frameworks */,
|
||||
545DB9BF2151169500CA77B8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FloatingPanel;
|
||||
productName = FloatingModalController;
|
||||
productReference = 545DB9C12151169500CA77B8 /* FloatingPanel.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
545DB9C92151169500CA77B8 /* FloatingPanelTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DB9D82151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanelTests" */;
|
||||
buildPhases = (
|
||||
545DB9C62151169500CA77B8 /* Sources */,
|
||||
545DB9C72151169500CA77B8 /* Frameworks */,
|
||||
545DB9C82151169500CA77B8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
545DB9CD2151169500CA77B8 /* PBXTargetDependency */,
|
||||
);
|
||||
name = FloatingPanelTests;
|
||||
productName = FloatingModalControllerTests;
|
||||
productReference = 545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
545DB9B82151169500CA77B8 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1010;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = scenee;
|
||||
TargetAttributes = {
|
||||
545DB9C02151169500CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
LastSwiftMigration = 1110;
|
||||
};
|
||||
545DB9C92151169500CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 545DB9BB2151169500CA77B8 /* Build configuration list for PBXProject "FloatingPanel" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 545DB9B72151169500CA77B8;
|
||||
productRefGroup = 545DB9C22151169500CA77B8 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
545DB9C02151169500CA77B8 /* FloatingPanel */,
|
||||
545DB9C92151169500CA77B8 /* FloatingPanelTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
545DB9BF2151169500CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9C82151169500CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
545DB9BD2151169500CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5469F4B224B30F1100537F8A /* Position.swift in Sources */,
|
||||
5469F4B024B30E1500537F8A /* LayoutAnchoring.swift in Sources */,
|
||||
54CDC5D3215B6D5A007D205C /* SurfaceView.swift in Sources */,
|
||||
54CFBFC3215CD045006B5735 /* Layout.swift in Sources */,
|
||||
5469F4B424B30F3500537F8A /* LayoutProperties.swift in Sources */,
|
||||
54CDC5D5215B6D8D007D205C /* BackdropView.swift in Sources */,
|
||||
54352E9821A521CA00CBCA08 /* PassthroughView.swift in Sources */,
|
||||
54CFBFC5215CD09C006B5735 /* Core.swift in Sources */,
|
||||
54ABD7AF216CCFF7002E6C13 /* Logging.swift in Sources */,
|
||||
545DB9E021511AC100CA77B8 /* Controller.swift in Sources */,
|
||||
54DBA3DC262E938500D75969 /* Extensions.swift in Sources */,
|
||||
5450EEE421646DF500135936 /* Behavior.swift in Sources */,
|
||||
545DBA2B2152383100CA77B8 /* GrabberView.swift in Sources */,
|
||||
54E3992727141F5100A8F9ED /* FloatingPanel.docc in Sources */,
|
||||
54352E9621A51A2500CBCA08 /* Transitioning.swift in Sources */,
|
||||
5469F4AE24B30D7E00537F8A /* State.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9C62151169500CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54A6B6B122968B530077F348 /* CoreTests.swift in Sources */,
|
||||
549C371F2361E15E007D8058 /* ExtensionTests.swift in Sources */,
|
||||
545DB9D02151169500CA77B8 /* ControllerTests.swift in Sources */,
|
||||
549E944522CF295D0050AECF /* StateTests.swift in Sources */,
|
||||
542753C622C49A6E00D17955 /* LayoutTests.swift in Sources */,
|
||||
54A6B6B82296A8520077F348 /* SurfaceViewTests.swift in Sources */,
|
||||
546055BF2333C4740069F400 /* TestSupports.swift in Sources */,
|
||||
547F7A9C2A6E946000303905 /* GestureTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
545DB9CD2151169500CA77B8 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 545DB9C02151169500CA77B8 /* FloatingPanel */;
|
||||
targetProxy = 545DB9CC2151169500CA77B8 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
545DB9D32151169500CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DB9D42151169500CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DB9D62151169500CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DB9D72151169500CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DB9D92151169500CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DB9DA2151169500CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
54E79ADF224F6C9800717BC6 /* Test */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
54E79AE0224F6C9800717BC6 /* Test */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "TEST DEBUG FP_LOG";
|
||||
SWIFT_COMPILATION_MODE = singlefile;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES;
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
54E79AE1224F6C9800717BC6 /* Test */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
545DB9BB2151169500CA77B8 /* Build configuration list for PBXProject "FloatingPanel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DB9D32151169500CA77B8 /* Debug */,
|
||||
54E79ADF224F6C9800717BC6 /* Test */,
|
||||
545DB9D42151169500CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DB9D52151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DB9D62151169500CA77B8 /* Debug */,
|
||||
54E79AE0224F6C9800717BC6 /* Test */,
|
||||
545DB9D72151169500CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DB9D82151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanelTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DB9D92151169500CA77B8 /* Debug */,
|
||||
54E79AE1224F6C9800717BC6 /* Test */,
|
||||
545DB9DA2151169500CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 545DB9B82151169500CA77B8 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>FILEHEADER</key>
|
||||
<string> Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
+23
-6
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -23,14 +23,33 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Test"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545DB9C02151169500CA77B8"
|
||||
BuildableName = "FloatingPanel.framework"
|
||||
BlueprintName = "FloatingPanel"
|
||||
ReferencedContainer = "container:FloatingPanel.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "545DB9C92151169500CA77B8"
|
||||
BuildableName = "FloatingPanelTests.xctest"
|
||||
BlueprintName = "FloatingPanelTests"
|
||||
ReferencedContainer = "container:FloatingPanel.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -51,8 +70,6 @@
|
||||
ReferencedContainer = "container:FloatingPanel.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
+9
-7
@@ -4,16 +4,15 @@
|
||||
<FileRef
|
||||
location = "group:README.md">
|
||||
</FileRef>
|
||||
<Group
|
||||
location = "group:Framework"
|
||||
name = "Framework">
|
||||
<FileRef
|
||||
location = "group:/Users/shin/Workspace/scenee/FloatingPanel/Framework/FloatingPanel.xcodeproj">
|
||||
</FileRef>
|
||||
</Group>
|
||||
<FileRef
|
||||
location = "group:FloatingPanel.xcodeproj">
|
||||
</FileRef>
|
||||
<Group
|
||||
location = "group:Examples"
|
||||
name = "Examples">
|
||||
<FileRef
|
||||
location = "group:Maps-SwiftUI/Maps-SwiftUI.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Maps/Maps.xcodeproj">
|
||||
</FileRef>
|
||||
@@ -23,5 +22,8 @@
|
||||
<FileRef
|
||||
location = "group:Samples/Samples.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:SamplesObjC/SamplesObjC.xcodeproj">
|
||||
</FileRef>
|
||||
</Group>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5450EEE421646DF500135936 /* FloatingPanelBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5450EEE321646DF500135936 /* FloatingPanelBehavior.swift */; };
|
||||
545DB9CB2151169500CA77B8 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 545DB9C12151169500CA77B8 /* FloatingPanel.framework */; };
|
||||
545DB9D02151169500CA77B8 /* ViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9CF2151169500CA77B8 /* ViewTests.swift */; };
|
||||
545DB9D22151169500CA77B8 /* FloatingPanelController.h in Headers */ = {isa = PBXBuildFile; fileRef = 545DB9C42151169500CA77B8 /* FloatingPanelController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
545DB9DE215118C800CA77B8 /* UIExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9DD215118C800CA77B8 /* UIExtensions.swift */; };
|
||||
545DB9E021511AC100CA77B8 /* FloatingPanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9DF21511AC100CA77B8 /* FloatingPanelController.swift */; };
|
||||
545DBA2B2152383100CA77B8 /* GrabberHandleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DBA2A2152383100CA77B8 /* GrabberHandleView.swift */; };
|
||||
54ABD7AF216CCFF7002E6C13 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54ABD7AE216CCFF7002E6C13 /* Logger.swift */; };
|
||||
54CDC5D3215B6D5A007D205C /* FloatingPanelSurfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D2215B6D5A007D205C /* FloatingPanelSurfaceView.swift */; };
|
||||
54CDC5D5215B6D8D007D205C /* FloatingPanelBackdropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D4215B6D8D007D205C /* FloatingPanelBackdropView.swift */; };
|
||||
54CFBFC3215CD045006B5735 /* FloatingPanelLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CFBFC2215CD045006B5735 /* FloatingPanelLayout.swift */; };
|
||||
54CFBFC5215CD09C006B5735 /* FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CFBFC4215CD09C006B5735 /* FloatingPanel.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
545DB9CC2151169500CA77B8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 545DB9B82151169500CA77B8 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 545DB9C02151169500CA77B8;
|
||||
remoteInfo = FloatingModalController;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5450EEE321646DF500135936 /* FloatingPanelBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelBehavior.swift; sourceTree = "<group>"; };
|
||||
545DB9C12151169500CA77B8 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DB9C42151169500CA77B8 /* FloatingPanelController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FloatingPanelController.h; sourceTree = "<group>"; };
|
||||
545DB9C52151169500CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FloatingPanelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DB9CF2151169500CA77B8 /* ViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewTests.swift; sourceTree = "<group>"; };
|
||||
545DB9D12151169500CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DB9DD215118C800CA77B8 /* UIExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIExtensions.swift; sourceTree = "<group>"; };
|
||||
545DB9DF21511AC100CA77B8 /* FloatingPanelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelController.swift; sourceTree = "<group>"; };
|
||||
545DBA2A2152383100CA77B8 /* GrabberHandleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrabberHandleView.swift; sourceTree = "<group>"; };
|
||||
54ABD7AE216CCFF7002E6C13 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||
54CDC5D2215B6D5A007D205C /* FloatingPanelSurfaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelSurfaceView.swift; sourceTree = "<group>"; };
|
||||
54CDC5D4215B6D8D007D205C /* FloatingPanelBackdropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelBackdropView.swift; sourceTree = "<group>"; };
|
||||
54CFBFC2215CD045006B5735 /* FloatingPanelLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelLayout.swift; sourceTree = "<group>"; };
|
||||
54CFBFC4215CD09C006B5735 /* FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanel.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
545DB9BE2151169500CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9C72151169500CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DB9CB2151169500CA77B8 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
545DB9B72151169500CA77B8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9C32151169500CA77B8 /* Sources */,
|
||||
545DB9CE2151169500CA77B8 /* Tests */,
|
||||
545DB9C22151169500CA77B8 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9C22151169500CA77B8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9C12151169500CA77B8 /* FloatingPanel.framework */,
|
||||
545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9C32151169500CA77B8 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9C52151169500CA77B8 /* Info.plist */,
|
||||
545DB9C42151169500CA77B8 /* FloatingPanelController.h */,
|
||||
545DB9DF21511AC100CA77B8 /* FloatingPanelController.swift */,
|
||||
54CFBFC4215CD09C006B5735 /* FloatingPanel.swift */,
|
||||
54CFBFC2215CD045006B5735 /* FloatingPanelLayout.swift */,
|
||||
5450EEE321646DF500135936 /* FloatingPanelBehavior.swift */,
|
||||
54CDC5D2215B6D5A007D205C /* FloatingPanelSurfaceView.swift */,
|
||||
54CDC5D4215B6D8D007D205C /* FloatingPanelBackdropView.swift */,
|
||||
545DBA2A2152383100CA77B8 /* GrabberHandleView.swift */,
|
||||
545DB9DD215118C800CA77B8 /* UIExtensions.swift */,
|
||||
54ABD7AE216CCFF7002E6C13 /* Logger.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DB9CE2151169500CA77B8 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9CF2151169500CA77B8 /* ViewTests.swift */,
|
||||
545DB9D12151169500CA77B8 /* Info.plist */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
545DB9BC2151169500CA77B8 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DB9D22151169500CA77B8 /* FloatingPanelController.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
545DB9C02151169500CA77B8 /* FloatingPanel */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DB9D52151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanel" */;
|
||||
buildPhases = (
|
||||
545DB9BC2151169500CA77B8 /* Headers */,
|
||||
545DB9BD2151169500CA77B8 /* Sources */,
|
||||
545DB9BE2151169500CA77B8 /* Frameworks */,
|
||||
545DB9BF2151169500CA77B8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FloatingPanel;
|
||||
productName = FloatingModalController;
|
||||
productReference = 545DB9C12151169500CA77B8 /* FloatingPanel.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
545DB9C92151169500CA77B8 /* FloatingPanelTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DB9D82151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanelTests" */;
|
||||
buildPhases = (
|
||||
545DB9C62151169500CA77B8 /* Sources */,
|
||||
545DB9C72151169500CA77B8 /* Frameworks */,
|
||||
545DB9C82151169500CA77B8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
545DB9CD2151169500CA77B8 /* PBXTargetDependency */,
|
||||
);
|
||||
name = FloatingPanelTests;
|
||||
productName = FloatingModalControllerTests;
|
||||
productReference = 545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
545DB9B82151169500CA77B8 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1000;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = scenee;
|
||||
TargetAttributes = {
|
||||
545DB9C02151169500CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
545DB9C92151169500CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 545DB9BB2151169500CA77B8 /* Build configuration list for PBXProject "FloatingPanel" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 545DB9B72151169500CA77B8;
|
||||
productRefGroup = 545DB9C22151169500CA77B8 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
545DB9C02151169500CA77B8 /* FloatingPanel */,
|
||||
545DB9C92151169500CA77B8 /* FloatingPanelTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
545DB9BF2151169500CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9C82151169500CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
545DB9BD2151169500CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54CDC5D3215B6D5A007D205C /* FloatingPanelSurfaceView.swift in Sources */,
|
||||
54CFBFC3215CD045006B5735 /* FloatingPanelLayout.swift in Sources */,
|
||||
54CDC5D5215B6D8D007D205C /* FloatingPanelBackdropView.swift in Sources */,
|
||||
54CFBFC5215CD09C006B5735 /* FloatingPanel.swift in Sources */,
|
||||
54ABD7AF216CCFF7002E6C13 /* Logger.swift in Sources */,
|
||||
545DB9E021511AC100CA77B8 /* FloatingPanelController.swift in Sources */,
|
||||
5450EEE421646DF500135936 /* FloatingPanelBehavior.swift in Sources */,
|
||||
545DBA2B2152383100CA77B8 /* GrabberHandleView.swift in Sources */,
|
||||
545DB9DE215118C800CA77B8 /* UIExtensions.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9C62151169500CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DB9D02151169500CA77B8 /* ViewTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
545DB9CD2151169500CA77B8 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 545DB9C02151169500CA77B8 /* FloatingPanel */;
|
||||
targetProxy = 545DB9CC2151169500CA77B8 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
545DB9D32151169500CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DB9D42151169500CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DB9D62151169500CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DB9D72151169500CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DB9D92151169500CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalControllerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DB9DA2151169500CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalControllerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
545DB9BB2151169500CA77B8 /* Build configuration list for PBXProject "FloatingPanel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DB9D32151169500CA77B8 /* Debug */,
|
||||
545DB9D42151169500CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DB9D52151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DB9D62151169500CA77B8 /* Debug */,
|
||||
545DB9D72151169500CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DB9D82151169500CA77B8 /* Build configuration list for PBXNativeTarget "FloatingPanelTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DB9D92151169500CA77B8 /* Debug */,
|
||||
545DB9DA2151169500CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 545DB9B82151169500CA77B8 /* Project object */;
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
//
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
///
|
||||
/// FloatingPanel presentation model
|
||||
///
|
||||
class FloatingPanel: NSObject, UIGestureRecognizerDelegate {
|
||||
/* Cause 'terminating with uncaught exception of type NSException' error on Swift Playground
|
||||
unowned let view: UIView
|
||||
*/
|
||||
let surfaceView: FloatingPanelSurfaceView
|
||||
let backdropView: FloatingPanelBackdropView
|
||||
|
||||
private unowned let viewcontroller: FloatingPanelController
|
||||
|
||||
weak var scrollView: UIScrollView? {
|
||||
didSet {
|
||||
configureScrollable()
|
||||
}
|
||||
}
|
||||
|
||||
var safeAreaInsets: UIEdgeInsets! {
|
||||
get {
|
||||
return layoutAdapter.safeAreaInsets
|
||||
}
|
||||
set {
|
||||
layoutAdapter.safeAreaInsets = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var state: FloatingPanelPosition = .tip {
|
||||
didSet {
|
||||
switch state {
|
||||
case .full:
|
||||
backdropView.alpha = layoutAdapter.layout.backdropAlpha
|
||||
default:
|
||||
backdropView.alpha = 0.0
|
||||
}
|
||||
configureScrollable()
|
||||
}
|
||||
}
|
||||
|
||||
var layoutAdapter: FloatingPanelLayoutAdapter
|
||||
var behavior: FloatingPanelBehavior
|
||||
private var animator: UIViewPropertyAnimator?
|
||||
private let panGesture: UIPanGestureRecognizer
|
||||
private var initialFrame: CGRect = .zero
|
||||
private var transOffsetY: CGFloat = 0
|
||||
private var interactionInProgress: Bool = false
|
||||
|
||||
init(_ vc: FloatingPanelController, layout: FloatingPanelLayout, behavior: FloatingPanelBehavior) {
|
||||
viewcontroller = vc
|
||||
surfaceView = vc.view as! FloatingPanelSurfaceView
|
||||
backdropView = FloatingPanelBackdropView()
|
||||
backdropView.backgroundColor = .black
|
||||
backdropView.alpha = 0.0
|
||||
|
||||
self.layoutAdapter = FloatingPanelLayoutAdapter(surfaceView: surfaceView, layout: layout)
|
||||
self.behavior = behavior
|
||||
|
||||
panGesture = UIPanGestureRecognizer()
|
||||
|
||||
if #available(iOS 11.0, *) {
|
||||
panGesture.name = "FloatingPanelSurface"
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
surfaceView.addGestureRecognizer(panGesture)
|
||||
panGesture.addTarget(self, action: #selector(handle(panGesture:)))
|
||||
panGesture.delegate = self
|
||||
}
|
||||
|
||||
func layoutViews(in vc: UIViewController) {
|
||||
unowned let view = vc.view!
|
||||
|
||||
view.insertSubview(backdropView, belowSubview: surfaceView)
|
||||
backdropView.frame = view.bounds
|
||||
|
||||
layoutAdapter.prepareLayout(toParent: vc)
|
||||
}
|
||||
|
||||
func move(to: FloatingPanelPosition, animated: Bool, completion: (() -> Void)? = nil) {
|
||||
if animated {
|
||||
let animator = behavior.presentAnimator(from: state, to: to)
|
||||
animator.addAnimations { [weak self] in
|
||||
self?.updateLayout(to: to)
|
||||
self?.state = to
|
||||
}
|
||||
animator.addCompletion { _ in
|
||||
completion?()
|
||||
}
|
||||
animator.startAnimation()
|
||||
} else {
|
||||
self.updateLayout(to: to)
|
||||
self.state = to
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
func present(animated: Bool, completion: (() -> Void)? = nil) {
|
||||
self.layoutAdapter.activateLayout(of: nil)
|
||||
move(to: layoutAdapter.layout.initialPosition, animated: animated, completion: completion)
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool, completion: (() -> Void)? = nil) {
|
||||
if animated {
|
||||
let animator = behavior.dismissAnimator(from: state)
|
||||
animator.addAnimations { [weak self] in
|
||||
self?.updateLayout(to: nil)
|
||||
}
|
||||
animator.addCompletion { _ in
|
||||
completion?()
|
||||
}
|
||||
animator.startAnimation()
|
||||
} else {
|
||||
self.updateLayout(to: nil)
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
|
||||
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
log.debug("gestureRecognizer", gestureRecognizer,
|
||||
"shouldRecognizeSimultaneouslyWith", otherGestureRecognizer)
|
||||
if #available(iOS 11.0, *) {
|
||||
log.debug("gestureRecognizer",
|
||||
String(describing: gestureRecognizer.name),
|
||||
"shouldRecognizeSimultaneouslyWith",
|
||||
String(describing: otherGestureRecognizer.name))
|
||||
}
|
||||
|
||||
switch (gestureRecognizer, otherGestureRecognizer) {
|
||||
case (panGesture, scrollView?.panGestureRecognizer):
|
||||
return state == .full
|
||||
case (panGesture, is UIPanGestureRecognizer):
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
// Do not begin any gestures until the pan gesture fails at non-full position.
|
||||
return gestureRecognizer == panGesture && state != .full
|
||||
}
|
||||
|
||||
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
private func configureScrollable() {
|
||||
switch state {
|
||||
case .full:
|
||||
scrollView?.isScrollEnabled = true
|
||||
default:
|
||||
scrollView?.isScrollEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
@objc func handle(panGesture: UIPanGestureRecognizer) {
|
||||
let translation = panGesture.translation(in: panGesture.view!.superview)
|
||||
let velocity = panGesture.velocity(in: panGesture.view)
|
||||
let location = panGesture.location(in: panGesture.view)
|
||||
|
||||
if #available(iOS 11.0, *) {
|
||||
log.debug("Gesture >>>>", panGesture.name!)
|
||||
}
|
||||
if let scrollView = scrollView, scrollView.frame.contains(location), interactionInProgress == false {
|
||||
log.debug("ScrollView.contentOffset >>>", scrollView.contentOffset)
|
||||
if state == .full {
|
||||
if scrollView.contentOffset.y > scrollView.contentOffsetZero.y {
|
||||
return
|
||||
}
|
||||
if scrollView.isDecelerating {
|
||||
return
|
||||
}
|
||||
if interactionInProgress == false, velocity.y < 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
scrollView.contentOffset.y = scrollView.contentOffsetZero.y
|
||||
}
|
||||
log.debug(panGesture.state, ">>>", "{ translation: \(translation), velocity: \(velocity) }")
|
||||
switch panGesture.state {
|
||||
case .began:
|
||||
panningBegan()
|
||||
case .changed:
|
||||
panningChange(with: translation)
|
||||
case .ended, .cancelled, .failed:
|
||||
panningEnd(with: translation, velocity: velocity)
|
||||
case .possible:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func panningBegan() {
|
||||
// A user interaction does not always start from Began state of the pan gesture
|
||||
// because it can be recognized in scrolling a content in a content view controller.
|
||||
// So I don't nothing here.
|
||||
log.debug("panningBegan \(initialFrame)")
|
||||
}
|
||||
|
||||
private func panningChange(with translation: CGPoint) {
|
||||
log.debug("panningChange")
|
||||
if interactionInProgress == false {
|
||||
startInteraction(with: translation)
|
||||
}
|
||||
var frame = initialFrame
|
||||
frame.origin.y = getCurrentY(from: initialFrame, with: translation)
|
||||
surfaceView.frame = frame
|
||||
viewcontroller.delegate?.floatingPanelDidMove(viewcontroller)
|
||||
backdropView.alpha = updateBackdropAlpha(with: translation)
|
||||
}
|
||||
|
||||
private func panningEnd(with translation: CGPoint, velocity: CGPoint) {
|
||||
log.debug("panningEnd")
|
||||
if interactionInProgress == false {
|
||||
initialFrame = surfaceView.frame
|
||||
}
|
||||
|
||||
let targetPosition = self.targetPosition(with: translation, velocity: velocity)
|
||||
let distance = self.distance(to: targetPosition, with: translation)
|
||||
|
||||
endInteraction(for: targetPosition)
|
||||
viewcontroller.delegate?.floatingPanelDidEndDragging(viewcontroller, withVelocity: velocity, targetPosition: targetPosition)
|
||||
viewcontroller.delegate?.floatingPanelWillBeginDecelerating(viewcontroller)
|
||||
startAnimation(to: targetPosition, at: distance, with: velocity)
|
||||
}
|
||||
|
||||
private func startInteraction(with translation: CGPoint) {
|
||||
log.debug("startInteraction")
|
||||
initialFrame = surfaceView.frame
|
||||
transOffsetY = translation.y
|
||||
viewcontroller.delegate?.floatingPanelWillBeginDragging(viewcontroller)
|
||||
if let scrollView = scrollView {
|
||||
scrollView.isScrollEnabled = false
|
||||
}
|
||||
|
||||
interactionInProgress = true
|
||||
}
|
||||
|
||||
private func endInteraction(for targetPosition: FloatingPanelPosition) {
|
||||
log.debug("endInteraction for \(targetPosition)")
|
||||
if let scrollView = scrollView {
|
||||
if targetPosition == .full {
|
||||
scrollView.isScrollEnabled = true
|
||||
}
|
||||
}
|
||||
interactionInProgress = false
|
||||
}
|
||||
|
||||
private func getCurrentY(from rect: CGRect, with translation: CGPoint) -> CGFloat {
|
||||
let dy = translation.y - transOffsetY
|
||||
let y = rect.offsetBy(dx: 0.0, dy: dy).origin.y
|
||||
|
||||
let topY = layoutAdapter.topY
|
||||
let topInset = layoutAdapter.topInset
|
||||
let topBuffer = layoutAdapter.layout.topInteractionBuffer
|
||||
|
||||
let bottomY = layoutAdapter.bottomY
|
||||
let bottomBuffer = layoutAdapter.layout.bottomInteractionBuffer
|
||||
|
||||
return max(topY - topInset + topBuffer, min(bottomY + bottomBuffer, y))
|
||||
}
|
||||
|
||||
private func startAnimation(to targetPosition: FloatingPanelPosition, at distance: CGFloat, with velocity: CGPoint) {
|
||||
let targetY = layoutAdapter.positionY(for: targetPosition)
|
||||
let velocityVector = (distance != 0) ? CGVector(dx: 0, dy: velocity.y/distance) : .zero
|
||||
let animator = behavior.interactionAnimator(to: targetPosition, with: velocityVector)
|
||||
animator.addAnimations { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if self.state == targetPosition {
|
||||
self.surfaceView.frame.origin.y = targetY
|
||||
} else {
|
||||
self.updateLayout(to: targetPosition)
|
||||
}
|
||||
self.state = targetPosition
|
||||
}
|
||||
animator.addCompletion { [weak self] pos in
|
||||
guard let self = self else { return }
|
||||
guard
|
||||
self.interactionInProgress == false,
|
||||
animator == self.animator,
|
||||
pos == .end
|
||||
else { return }
|
||||
self.finishAnimation(at: targetPosition)
|
||||
}
|
||||
animator.startAnimation()
|
||||
self.animator = animator
|
||||
}
|
||||
|
||||
private func finishAnimation(at targetPosition: FloatingPanelPosition) {
|
||||
log.debug("finishAnimation \(targetPosition)")
|
||||
self.animator = nil
|
||||
self.viewcontroller.delegate?.floatingPanelDidEndDecelerating(self.viewcontroller)
|
||||
}
|
||||
|
||||
private func updateLayout(to target: FloatingPanelPosition?) {
|
||||
self.layoutAdapter.activateLayout(of: target)
|
||||
}
|
||||
|
||||
private func updateBackdropAlpha(with translation: CGPoint) -> CGFloat {
|
||||
let topY = layoutAdapter.topY
|
||||
let middleY = layoutAdapter.middleY
|
||||
let currentY = getCurrentY(from: initialFrame, with: translation)
|
||||
return (1 - (currentY - topY) / (middleY - topY)) * layoutAdapter.layout.backdropAlpha
|
||||
}
|
||||
|
||||
// Animation handling
|
||||
private func distance(to targetPosition: FloatingPanelPosition, with translation: CGPoint) -> CGFloat {
|
||||
let topY = layoutAdapter.topY
|
||||
let middleY = layoutAdapter.middleY
|
||||
let bottomY = layoutAdapter.bottomY
|
||||
let currentY = getCurrentY(from: initialFrame, with: translation)
|
||||
switch targetPosition {
|
||||
case .full:
|
||||
return CGFloat(fabs(Double(currentY - topY)))
|
||||
case .half:
|
||||
return CGFloat(fabs(Double(currentY - middleY)))
|
||||
case .tip:
|
||||
return CGFloat(fabs(Double(currentY - bottomY)))
|
||||
}
|
||||
}
|
||||
|
||||
// Distance travelled after decelerating to zero velocity at a constant rate.
|
||||
// Refer to the slides p176 of [Designing Fluid Interfaces](https://developer.apple.com/videos/play/wwdc2018/803/)
|
||||
private func project(initialVelocity: CGFloat) -> CGFloat {
|
||||
let decelerationRate = UIScrollView.DecelerationRate.normal.rawValue
|
||||
return (initialVelocity / 1000.0) * decelerationRate / (1.0 - decelerationRate)
|
||||
}
|
||||
|
||||
private func targetPosition(with translation: CGPoint, velocity: CGPoint) -> (FloatingPanelPosition) {
|
||||
let currentY = getCurrentY(from: initialFrame, with: translation)
|
||||
let supportedPositions = Set(layoutAdapter.layout.supportedPositions)
|
||||
|
||||
assert(supportedPositions.count > 1)
|
||||
|
||||
switch supportedPositions {
|
||||
case Set([.full, .half]):
|
||||
return targetPosition(from: [.half, .tip], at: currentY, velocity: velocity)
|
||||
case Set([.half, .tip]):
|
||||
return targetPosition(from: [.half, .tip], at: currentY, velocity: velocity)
|
||||
case Set([.full, .tip]):
|
||||
return targetPosition(from: [.full, .tip], at: currentY, velocity: velocity)
|
||||
default:
|
||||
/*
|
||||
[topY|full]---[th1]---[middleY|default]---[th2]---[bottomY|collapsed]
|
||||
*/
|
||||
let topY = layoutAdapter.topY
|
||||
let middleY = layoutAdapter.middleY
|
||||
let bottomY = layoutAdapter.bottomY
|
||||
|
||||
let th1 = (topY + middleY) / 2
|
||||
let th2 = (middleY + bottomY) / 2
|
||||
|
||||
switch currentY {
|
||||
case ..<th1:
|
||||
if project(initialVelocity: velocity.y) >= (middleY - currentY) {
|
||||
return .half
|
||||
} else {
|
||||
return .full
|
||||
}
|
||||
case ...middleY:
|
||||
if project(initialVelocity: velocity.y) <= (topY - currentY) {
|
||||
return .full
|
||||
} else {
|
||||
return .half
|
||||
}
|
||||
case ..<th2:
|
||||
if project(initialVelocity: velocity.y) >= (bottomY - currentY) {
|
||||
return .tip
|
||||
} else {
|
||||
return .half
|
||||
}
|
||||
default:
|
||||
if project(initialVelocity: velocity.y) <= (middleY - currentY) {
|
||||
return .half
|
||||
} else {
|
||||
return .tip
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func targetPosition(from positions: [FloatingPanelPosition], at currentY: CGFloat, velocity: CGPoint) -> FloatingPanelPosition {
|
||||
assert(positions.count == 2)
|
||||
|
||||
let top = positions[0]
|
||||
let bottom = positions[1]
|
||||
|
||||
let topY = layoutAdapter.positionY(for: top)
|
||||
let bottomY = layoutAdapter.positionY(for: bottom)
|
||||
|
||||
let th = (topY + bottomY) / 2
|
||||
|
||||
switch currentY {
|
||||
case ..<th:
|
||||
if project(initialVelocity: velocity.y) >= (bottomY - currentY) {
|
||||
return bottom
|
||||
} else {
|
||||
return top
|
||||
}
|
||||
default:
|
||||
if project(initialVelocity: velocity.y) <= (topY - currentY) {
|
||||
return top
|
||||
} else {
|
||||
return bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/09/26.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// A view that presents a backdrop interface behind a floating panel.
|
||||
public class FloatingPanelBackdropView: UIView { }
|
||||
@@ -1,67 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/10/03.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public protocol FloatingPanelBehavior {
|
||||
// Returns a UIViewPropertyAnimator object in interacting a floating panel by a user pan gesture
|
||||
func interactionAnimator(to targetPosition: FloatingPanelPosition, with velocity: CGVector) -> UIViewPropertyAnimator
|
||||
|
||||
// Returns a UIViewPropertyAnimator object to present a floating panel
|
||||
func presentAnimator(from: FloatingPanelPosition, to: FloatingPanelPosition) -> UIViewPropertyAnimator
|
||||
// Returns a UIViewPropertyAnimator object to dismiss a floating panel
|
||||
func dismissAnimator(from: FloatingPanelPosition) -> UIViewPropertyAnimator
|
||||
}
|
||||
|
||||
public extension FloatingPanelBehavior {
|
||||
func presentAnimator(from: FloatingPanelPosition, to: FloatingPanelPosition) -> UIViewPropertyAnimator {
|
||||
return UIViewPropertyAnimator(duration: 0.25, curve: .easeInOut)
|
||||
}
|
||||
|
||||
func dismissAnimator(from: FloatingPanelPosition) -> UIViewPropertyAnimator {
|
||||
return UIViewPropertyAnimator(duration: 0.25, curve: .easeInOut)
|
||||
}
|
||||
}
|
||||
|
||||
class FloatingPanelDefaultBehavior: FloatingPanelBehavior {
|
||||
func interactionAnimator(to targetPosition: FloatingPanelPosition, with velocity: CGVector) -> UIViewPropertyAnimator {
|
||||
let timing = timeingCurve(to: targetPosition, with: velocity)
|
||||
let duration = getDuration(with: velocity)
|
||||
return UIViewPropertyAnimator(duration: duration, timingParameters: timing)
|
||||
}
|
||||
|
||||
private let velocityThreshold: CGFloat = 8.0
|
||||
private func getDuration(with velocity: CGVector) -> TimeInterval {
|
||||
let dy = abs(velocity.dy)
|
||||
switch dy {
|
||||
case ..<1.0:
|
||||
return 0.6
|
||||
case 1.0..<velocityThreshold:
|
||||
let a = ((dy - 1.0) / (velocityThreshold - 1.0))
|
||||
return TimeInterval(0.6 - (0.2 * a))
|
||||
case velocityThreshold...:
|
||||
return 0.4
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
private func timeingCurve(to: FloatingPanelPosition, with velocity: CGVector) -> UITimingCurveProvider {
|
||||
log.debug("velocity", velocity)
|
||||
let damping = self.getDamping(with: velocity)
|
||||
let springTiming = UISpringTimingParameters(dampingRatio: damping,
|
||||
initialVelocity: velocity)
|
||||
return springTiming
|
||||
}
|
||||
|
||||
private func getDamping(with velocity: CGVector) -> CGFloat {
|
||||
let dy = abs(velocity.dy)
|
||||
if dy > velocityThreshold {
|
||||
return 0.7
|
||||
} else {
|
||||
return 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/09/18.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
FOUNDATION_EXPORT double FloatingPanelVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char FloatingPanelVersionString[];
|
||||
@@ -1,239 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/09/18.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public protocol FloatingPanelControllerDelegate: class {
|
||||
// if it returns nil, FloatingPanelController uses the default layout
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout?
|
||||
|
||||
// if it returns nil, FloatingPanelController uses the default behavior
|
||||
func floatingPanel(_ vc: FloatingPanelController, behaviorFor newCollection: UITraitCollection) -> FloatingPanelBehavior?
|
||||
|
||||
func floatingPanelDidMove(_ vc: FloatingPanelController) // any offset changes
|
||||
|
||||
// called on start of dragging (may require some time and or distance to move)
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController)
|
||||
// called on finger up if the user dragged. velocity is in points/second.
|
||||
func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition)
|
||||
func floatingPanelWillBeginDecelerating(_ vc: FloatingPanelController) // called on finger up as we are moving
|
||||
func floatingPanelDidEndDecelerating(_ vc: FloatingPanelController) // called when scroll view grinds to a halt
|
||||
}
|
||||
|
||||
public extension FloatingPanelControllerDelegate {
|
||||
func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? {
|
||||
return nil
|
||||
}
|
||||
func floatingPanel(_ vc: FloatingPanelController, behaviorFor newCollection: UITraitCollection) -> FloatingPanelBehavior? {
|
||||
return nil
|
||||
}
|
||||
func floatingPanelDidMove(_ vc: FloatingPanelController) {}
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {}
|
||||
func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition) {}
|
||||
func floatingPanelWillBeginDecelerating(_ vc: FloatingPanelController) {}
|
||||
func floatingPanelDidEndDecelerating(_ vc: FloatingPanelController) {}
|
||||
}
|
||||
|
||||
public enum FloatingPanelPosition: Int {
|
||||
case full
|
||||
case half
|
||||
case tip
|
||||
}
|
||||
|
||||
///
|
||||
/// A container view controller to display a floating panel to present contents in parallel as a user wants.
|
||||
///
|
||||
public class FloatingPanelController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate {
|
||||
|
||||
/// The delegate of the floating panel controller object.
|
||||
public weak var delegate: FloatingPanelControllerDelegate?
|
||||
|
||||
/// Returns the surface view managed by the controller object. It's the same as `self.view`.
|
||||
public var surfaceView: FloatingPanelSurfaceView! {
|
||||
return view as? FloatingPanelSurfaceView
|
||||
}
|
||||
|
||||
/// Returns the backdrop view managed by the controller object.
|
||||
public var backdropView: FloatingPanelBackdropView! {
|
||||
return floatingPanel.backdropView
|
||||
}
|
||||
|
||||
/// Returns the scroll view that the conroller tracks.
|
||||
public weak var scrollView: UIScrollView? {
|
||||
return floatingPanel.scrollView
|
||||
}
|
||||
|
||||
/// The current position of the floating panel controller's contents.
|
||||
public var position: FloatingPanelPosition {
|
||||
return floatingPanel.state
|
||||
}
|
||||
|
||||
private var floatingPanel: FloatingPanel!
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
/// Initialize a newly created a floating panel controller.
|
||||
public init() {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
/// Creates the view that the controller manages.
|
||||
override public func loadView() {
|
||||
assert(self.storyboard == nil, "Storyboard isn't supported")
|
||||
|
||||
let view = FloatingPanelSurfaceView()
|
||||
view.backgroundColor = .white
|
||||
|
||||
self.view = view as UIView
|
||||
|
||||
let layout = fetchLayout(for: self.traitCollection)
|
||||
let behavior = fetchBehavior(for: self.traitCollection)
|
||||
floatingPanel = FloatingPanel(self,
|
||||
layout: layout,
|
||||
behavior: behavior)
|
||||
}
|
||||
|
||||
public override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.willTransition(to: newCollection, with: coordinator)
|
||||
|
||||
// Change layout for a new trait collection
|
||||
floatingPanel.layoutAdapter.layout = fetchLayout(for: newCollection)
|
||||
floatingPanel.behavior = fetchBehavior(for: newCollection)
|
||||
|
||||
guard let parent = parent else { fatalError() }
|
||||
|
||||
floatingPanel.layoutAdapter.prepareLayout(toParent: parent)
|
||||
floatingPanel.layoutAdapter.activateLayout(of: floatingPanel.state)
|
||||
}
|
||||
|
||||
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
guard previousTraitCollection != traitCollection else { return }
|
||||
|
||||
if let parent = parent {
|
||||
floatingPanel.safeAreaInsets = parent.layoutInsets
|
||||
}
|
||||
floatingPanel.layoutAdapter.updateHeight()
|
||||
floatingPanel.backdropView.isHidden = (traitCollection.verticalSizeClass == .compact)
|
||||
}
|
||||
|
||||
public override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
// Must set `parent.view.layoutInsets` to floatingPanel.safeAreaInsets` here
|
||||
// because it ensures that parent.view.layoutInsets` has a correct value.
|
||||
if let parent = parent {
|
||||
floatingPanel.safeAreaInsets = parent.layoutInsets
|
||||
floatingPanel.backdropView.frame = parent.view.bounds
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchLayout(for traitCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
switch traitCollection.verticalSizeClass {
|
||||
case .compact:
|
||||
return self.delegate?.floatingPanel(self, layoutFor: traitCollection) ?? FloatingPanelDefaultLandscapeLayout()
|
||||
default:
|
||||
return self.delegate?.floatingPanel(self, layoutFor: traitCollection) ?? FloatingPanelDefaultLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchBehavior(for traitCollection: UITraitCollection) -> FloatingPanelBehavior {
|
||||
return self.delegate?.floatingPanel(self, behaviorFor: traitCollection) ?? FloatingPanelDefaultBehavior()
|
||||
}
|
||||
|
||||
// MARK: Container view controller responsibilities
|
||||
|
||||
/// Adds the controller as a child of the specified view controller.
|
||||
/// - Parameters:
|
||||
/// - parent: A parent view controller object that displays FloatingPanelController's view. A conatiner view controller object isn't applicable.
|
||||
/// - belowView: Insert the surface view managed by the controller below the specified view. As default, the surface view will be added to the end of the parent list of subviews.
|
||||
/// - animated: Pass true to animate the presentation; otherwise, pass false.
|
||||
public func add(toParent parent: UIViewController, belowView: UIView? = nil, animated: Bool = false) {
|
||||
guard self.parent == nil else {
|
||||
log.warning("Already added to a parent(\(parent))")
|
||||
return
|
||||
}
|
||||
precondition((parent is UINavigationController) == false, "UINavigationController displays only one child view controller at a time.")
|
||||
precondition((parent is UITableViewController) == false, "UITableViewController should not be the parent because the view hierarchy will be break in reusing cells.")
|
||||
precondition((parent is UICollectionViewController) == false, "UICollectionViewController should not be the parent because the view hierarchy will be break in reusing cells.")
|
||||
|
||||
view.frame = parent.view.bounds
|
||||
if let belowView = belowView {
|
||||
parent.view.insertSubview(self.view, belowSubview: belowView)
|
||||
} else {
|
||||
parent.view.addSubview(self.view)
|
||||
}
|
||||
|
||||
parent.addChild(self)
|
||||
|
||||
// Must set a layout again here because `self.traitCollection` is applied correctly on it's added to a parent VC
|
||||
floatingPanel.layoutAdapter.layout = fetchLayout(for: traitCollection)
|
||||
floatingPanel.layoutViews(in: parent)
|
||||
floatingPanel.present(animated: animated) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.didMove(toParent: parent)
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the view controller from its parent.
|
||||
/// - Parameters:
|
||||
/// - animated: Pass true to animate the presentation; otherwise, pass false.
|
||||
/// - completion: The block to execute after the view controller is dismissed. This block has no return value and takes no parameters. You may specify nil for this parameter.
|
||||
public func removeFromParent(animated: Bool = false, completion: (() -> Void)? = nil) {
|
||||
guard self.parent != nil else { return }
|
||||
|
||||
floatingPanel.dismiss(animated: animated) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.willMove(toParent: nil)
|
||||
self.view.removeFromSuperview()
|
||||
self.removeFromParent()
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the position to the specified position.
|
||||
/// - Parameters:
|
||||
/// - to: Pass a FloatingPanelPosition value to move the surface view to the position.
|
||||
/// - animated: Pass true to animate the presentation; otherwise, pass false.
|
||||
/// - completion: The block to execute after the view controller is dismissed. This block has no return value and takes no parameters. You may specify nil for this parameter.
|
||||
public func move(to: FloatingPanelPosition, animated: Bool, completion: (() -> Void)? = nil) {
|
||||
floatingPanel.move(to: to, animated: animated, completion: completion)
|
||||
}
|
||||
|
||||
/// Presents the specified view controller as the content view controller in the surface view interface.
|
||||
public override func show(_ vc: UIViewController, sender: Any?) {
|
||||
let surfaceView = self.view as! FloatingPanelSurfaceView
|
||||
surfaceView.contentView.addSubview(vc.view)
|
||||
vc.view.frame = surfaceView.contentView.bounds
|
||||
vc.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
vc.view.topAnchor.constraint(equalTo: surfaceView.contentView.topAnchor, constant: 0.0),
|
||||
vc.view.leftAnchor.constraint(equalTo: surfaceView.contentView.leftAnchor, constant: 0.0),
|
||||
vc.view.rightAnchor.constraint(equalTo: surfaceView.contentView.rightAnchor, constant: 0.0),
|
||||
vc.view.bottomAnchor.constraint(equalTo: surfaceView.contentView.bottomAnchor, constant: 0.0),
|
||||
])
|
||||
addChild(vc)
|
||||
vc.didMove(toParent: self)
|
||||
}
|
||||
|
||||
/// Tracks the specified scroll view for the inteface to correspond with the scroll pan gesture.
|
||||
public func track(scrollView: UIScrollView) {
|
||||
floatingPanel.scrollView = scrollView
|
||||
}
|
||||
|
||||
/// Returns the y-coordinate of the point at the origin of the surface view
|
||||
public func originYOfSurface(for pos: FloatingPanelPosition) -> CGFloat {
|
||||
switch pos {
|
||||
case .full:
|
||||
return floatingPanel.layoutAdapter.topY
|
||||
case .half:
|
||||
return floatingPanel.layoutAdapter.middleY
|
||||
case .tip:
|
||||
return floatingPanel.layoutAdapter.bottomY
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/09/27.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public protocol FloatingPanelLayout: class {
|
||||
/// Returns the initial position of a floating panel
|
||||
var initialPosition: FloatingPanelPosition { get }
|
||||
/// Returns an array of FloatingPanelPosition object to tell the applicable position the floating panel controller
|
||||
var supportedPositions: [FloatingPanelPosition] { get }
|
||||
|
||||
/// Return the interaction buffer of full position. Default is 6.0.
|
||||
var topInteractionBuffer: CGFloat { get }
|
||||
/// Return the interaction buffer of full position. Default is 6.0.
|
||||
var bottomInteractionBuffer: CGFloat { get }
|
||||
|
||||
/// Returns a CGFloat value for a floating panel position(full, half, tip).
|
||||
/// A value for full position indicates an inset from the safe area top.
|
||||
/// On the other hand, values fro half and tip positions indicate insets from the safe area bottom.
|
||||
/// If a position doesn't contain the supported positions, return nil.
|
||||
func insetFor(position: FloatingPanelPosition) -> CGFloat?
|
||||
/// Returns layout constraints for a surface view of a floaitng panel.
|
||||
/// The layout constraints must not include ones for topAnchor and bottomAnchor
|
||||
/// because constarints for them will be added by the floating panel controller.
|
||||
func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint]
|
||||
|
||||
/// Return the backdrop alpha of black color in full position. Default is 0.3.
|
||||
var backdropAlpha: CGFloat { get }
|
||||
}
|
||||
|
||||
public extension FloatingPanelLayout {
|
||||
var backdropAlpha: CGFloat { return 0.3 }
|
||||
var topInteractionBuffer: CGFloat { return 6.0 }
|
||||
var bottomInteractionBuffer: CGFloat { return 6.0 }
|
||||
}
|
||||
|
||||
public class FloatingPanelDefaultLayout: FloatingPanelLayout {
|
||||
public var supportedPositions: [FloatingPanelPosition] {
|
||||
return [.full, .half, .tip]
|
||||
}
|
||||
|
||||
public var initialPosition: FloatingPanelPosition {
|
||||
return .half
|
||||
}
|
||||
|
||||
public func insetFor(position: FloatingPanelPosition) -> CGFloat? {
|
||||
switch position {
|
||||
case .full: return 18.0
|
||||
case .half: return 262.0
|
||||
case .tip: return 69.0
|
||||
}
|
||||
}
|
||||
|
||||
public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
return [
|
||||
surfaceView.leftAnchor.constraint(equalTo: view.sideLayoutGuide.leftAnchor, constant: 0.0),
|
||||
surfaceView.rightAnchor.constraint(equalTo: view.sideLayoutGuide.rightAnchor, constant: 0.0),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public class FloatingPanelDefaultLandscapeLayout: FloatingPanelLayout {
|
||||
public var initialPosition: FloatingPanelPosition {
|
||||
return .tip
|
||||
}
|
||||
public var supportedPositions: [FloatingPanelPosition] {
|
||||
return [.full, .tip]
|
||||
}
|
||||
|
||||
public func insetFor(position: FloatingPanelPosition) -> CGFloat? {
|
||||
switch position {
|
||||
case .full: return 16.0
|
||||
case .tip: return 69.0
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
return [
|
||||
surfaceView.leftAnchor.constraint(equalTo: view.sideLayoutGuide.leftAnchor, constant: 8.0),
|
||||
surfaceView.widthAnchor.constraint(equalToConstant: 291),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FloatingPanelLayoutAdapter {
|
||||
private weak var surfaceView: FloatingPanelSurfaceView!
|
||||
|
||||
var layout: FloatingPanelLayout
|
||||
|
||||
var safeAreaInsets: UIEdgeInsets = .zero
|
||||
|
||||
private var heightBuffer: CGFloat = 88.0 // For bounce
|
||||
private var fixedConstraints: [NSLayoutConstraint] = []
|
||||
private var fullConstraints: [NSLayoutConstraint] = []
|
||||
private var halfConstraints: [NSLayoutConstraint] = []
|
||||
private var tipConstraints: [NSLayoutConstraint] = []
|
||||
private var offConstraints: [NSLayoutConstraint] = []
|
||||
private var heightConstraints: NSLayoutConstraint? = nil
|
||||
|
||||
var topInset: CGFloat {
|
||||
return layout.insetFor(position: .full) ?? 0.0
|
||||
}
|
||||
var halfInset: CGFloat {
|
||||
return layout.insetFor(position: .half) ?? 0.0
|
||||
}
|
||||
var tipInset: CGFloat {
|
||||
return layout.insetFor(position: .tip) ?? 0.0
|
||||
}
|
||||
|
||||
var topY: CGFloat {
|
||||
return (safeAreaInsets.top + topInset)
|
||||
}
|
||||
|
||||
var middleY: CGFloat {
|
||||
return surfaceView.superview!.bounds.height - (safeAreaInsets.bottom + halfInset)
|
||||
}
|
||||
|
||||
var bottomY: CGFloat {
|
||||
return surfaceView.superview!.bounds.height - (safeAreaInsets.bottom + tipInset)
|
||||
}
|
||||
|
||||
func positionY(for pos: FloatingPanelPosition) -> CGFloat {
|
||||
switch pos {
|
||||
case .full:
|
||||
return topY
|
||||
case .half:
|
||||
return middleY
|
||||
case .tip:
|
||||
return bottomY
|
||||
}
|
||||
}
|
||||
|
||||
init(surfaceView: FloatingPanelSurfaceView, layout: FloatingPanelLayout) {
|
||||
self.layout = layout
|
||||
self.surfaceView = surfaceView
|
||||
|
||||
// Verify layout configurations
|
||||
assert(layout.supportedPositions.count > 1)
|
||||
assert(layout.supportedPositions.contains(layout.initialPosition))
|
||||
if halfInset > 0 {
|
||||
assert(halfInset >= tipInset)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareLayout(toParent parent: UIViewController) {
|
||||
surfaceView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.deactivate(fixedConstraints + fullConstraints + halfConstraints + tipConstraints + offConstraints)
|
||||
|
||||
fixedConstraints = layout.prepareLayout(surfaceView: surfaceView, in: parent.view!)
|
||||
|
||||
fullConstraints = [
|
||||
surfaceView.topAnchor.constraint(equalTo: parent.layoutGuide.topAnchor,
|
||||
constant: topInset),
|
||||
]
|
||||
halfConstraints = [
|
||||
surfaceView.topAnchor.constraint(equalTo: parent.layoutGuide.bottomAnchor,
|
||||
constant: -halfInset),
|
||||
]
|
||||
tipConstraints = [
|
||||
surfaceView.topAnchor.constraint(equalTo: parent.layoutGuide.bottomAnchor,
|
||||
constant: -tipInset),
|
||||
]
|
||||
offConstraints = [
|
||||
surfaceView.topAnchor.constraint(equalTo: parent.layoutGuide.bottomAnchor, constant: 0.0),
|
||||
]
|
||||
}
|
||||
|
||||
// The method is separated from prepareLayout(to:) for the rotation support
|
||||
// It must be called in FloatingPanelController.traitCollectionDidChange(_:)
|
||||
func updateHeight() {
|
||||
defer {
|
||||
UIView.performWithoutAnimation {
|
||||
surfaceView.superview!.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
if let heightConstraints = self.heightConstraints {
|
||||
NSLayoutConstraint.deactivate([heightConstraints])
|
||||
}
|
||||
let heightConstraints = surfaceView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height + heightBuffer)
|
||||
NSLayoutConstraint.activate([heightConstraints])
|
||||
self.heightConstraints = heightConstraints
|
||||
}
|
||||
|
||||
func activateLayout(of state: FloatingPanelPosition?) {
|
||||
defer {
|
||||
surfaceView.superview!.layoutIfNeeded()
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate(fixedConstraints)
|
||||
|
||||
guard var state = state else {
|
||||
NSLayoutConstraint.deactivate(fullConstraints + halfConstraints + tipConstraints)
|
||||
NSLayoutConstraint.activate(offConstraints)
|
||||
return
|
||||
}
|
||||
|
||||
if layout.supportedPositions.contains(state) == false {
|
||||
state = layout.initialPosition
|
||||
}
|
||||
|
||||
NSLayoutConstraint.deactivate(fullConstraints + halfConstraints + tipConstraints + offConstraints)
|
||||
switch state {
|
||||
case .full:
|
||||
NSLayoutConstraint.deactivate(halfConstraints + tipConstraints + offConstraints)
|
||||
NSLayoutConstraint.activate(fullConstraints)
|
||||
case .half:
|
||||
NSLayoutConstraint.deactivate(fullConstraints + tipConstraints + offConstraints)
|
||||
NSLayoutConstraint.activate(halfConstraints)
|
||||
case .tip:
|
||||
NSLayoutConstraint.deactivate(fullConstraints + halfConstraints + offConstraints)
|
||||
NSLayoutConstraint.activate(tipConstraints)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/09/26.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FloatingPanelSurfaceContentView: UIView {}
|
||||
|
||||
/// A view that presents a surface interface in a floating panel.
|
||||
public class FloatingPanelSurfaceView: UIView {
|
||||
|
||||
/// A GrabberHandleView object displayed at the top of the surface view
|
||||
public var grabberHandle: GrabberHandleView!
|
||||
|
||||
/// A UIView object that can have the surface view added to it.
|
||||
public var contentView: UIView!
|
||||
|
||||
private var color: UIColor? = .white { didSet { setNeedsDisplay() } }
|
||||
|
||||
public override var backgroundColor: UIColor? {
|
||||
get { return color }
|
||||
set {
|
||||
color = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// The radius to use when drawing rounded corners
|
||||
public var cornerRadius: CGFloat = 0.0 { didSet { setNeedsLayout() } }
|
||||
|
||||
/// A Boolean indicating whether the surface shadow is displayed.
|
||||
public var shadowHidden: Bool = false { didSet { setNeedsLayout() } }
|
||||
|
||||
/// The color of the surface shadow.
|
||||
public var shadowColor: UIColor = .black { didSet { setNeedsLayout() } }
|
||||
|
||||
/// The offset (in points) of the surface shadow.
|
||||
public var shadowOffset: CGSize = CGSize(width: 0.0, height: 1.0) { didSet { setNeedsLayout() } }
|
||||
|
||||
/// The opacity of the surface shadow.
|
||||
public var shadowOpacity: Float = 0.2 { didSet { setNeedsLayout() } }
|
||||
|
||||
/// The blur radius (in points) used to render the surface shadow.
|
||||
public var shadowRadius: CGFloat = 3 { didSet { setNeedsLayout() } }
|
||||
|
||||
/// The width of the surface border.
|
||||
public var borderColor: UIColor? { didSet { setNeedsLayout() } }
|
||||
|
||||
/// The color of the surface border.
|
||||
public var borderWidth: CGFloat = 0.0 { didSet { setNeedsLayout() } }
|
||||
|
||||
|
||||
private var shadowLayer: CAShapeLayer! { didSet { setNeedsLayout() } }
|
||||
public struct Default {
|
||||
public static let grabberTopPadding: CGFloat = 6.0
|
||||
}
|
||||
private var topGrabberBarHeight: CGFloat {
|
||||
return Default.grabberTopPadding * 2 + GrabberHandleView.Default.height
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
render()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
render()
|
||||
}
|
||||
|
||||
private func render() {
|
||||
super.backgroundColor = .clear
|
||||
|
||||
let contentView = FloatingPanelSurfaceContentView()
|
||||
addSubview(contentView)
|
||||
self.contentView = contentView as UIView
|
||||
// contentView.backgroundColor = .lightGray
|
||||
contentView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
contentView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
|
||||
contentView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0.0),
|
||||
contentView.rightAnchor.constraint(equalTo: rightAnchor, constant: 0.0),
|
||||
contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
|
||||
])
|
||||
|
||||
let grabberHandle = GrabberHandleView()
|
||||
addSubview(grabberHandle)
|
||||
self.grabberHandle = grabberHandle
|
||||
|
||||
grabberHandle.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
grabberHandle.topAnchor.constraint(equalTo: topAnchor, constant: Default.grabberTopPadding),
|
||||
grabberHandle.widthAnchor.constraint(equalToConstant: grabberHandle.frame.width),
|
||||
grabberHandle.heightAnchor.constraint(equalToConstant: grabberHandle.frame.height),
|
||||
grabberHandle.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
updateShadowLayer()
|
||||
// Don't use `contentView.layer.mask` because of UIVisualEffectView issue on ios10, https://forums.developer.apple.com/thread/50854
|
||||
contentView.layer.cornerRadius = cornerRadius
|
||||
contentView.clipsToBounds = true
|
||||
contentView.layer.borderColor = borderColor?.cgColor
|
||||
contentView.layer.borderWidth = borderWidth
|
||||
}
|
||||
|
||||
private func updateShadowLayer() {
|
||||
if shadowLayer != nil {
|
||||
shadowLayer.removeFromSuperlayer()
|
||||
}
|
||||
shadowLayer = makeShadowLayer()
|
||||
layer.insertSublayer(shadowLayer, at: 0)
|
||||
}
|
||||
|
||||
private func makeShadowLayer() -> CAShapeLayer {
|
||||
log.debug("SurfaceView bounds", bounds)
|
||||
let shadowLayer = CAShapeLayer()
|
||||
let path = UIBezierPath(roundedRect: bounds,
|
||||
byRoundingCorners: [.topLeft, .topRight],
|
||||
cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
|
||||
shadowLayer.path = path.cgPath
|
||||
shadowLayer.fillColor = color?.cgColor
|
||||
if shadowHidden == false {
|
||||
shadowLayer.shadowPath = shadowLayer.path
|
||||
shadowLayer.shadowColor = shadowColor.cgColor
|
||||
shadowLayer.shadowOffset = shadowOffset
|
||||
shadowLayer.shadowOpacity = shadowOpacity
|
||||
shadowLayer.shadowRadius = shadowRadius
|
||||
}
|
||||
return shadowLayer
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
//
|
||||
// Created by Shin Yamamoto on 2018/09/19.
|
||||
// Copyright © 2018 scenee. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public class GrabberHandleView: UIView {
|
||||
public struct Default {
|
||||
public static let width: CGFloat = 36.0
|
||||
public static let height: CGFloat = 5.0
|
||||
public static let barColor = UIColor(displayP3Red: 0.76, green: 0.77, blue: 0.76, alpha: 1.0)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
render()
|
||||
}
|
||||
|
||||
init() {
|
||||
let size = CGSize(width: Default.width,
|
||||
height: Default.height)
|
||||
super.init(frame: CGRect(origin: .zero, size: size))
|
||||
self.backgroundColor = Default.barColor
|
||||
render()
|
||||
}
|
||||
private func render() {
|
||||
self.layer.masksToBounds = true
|
||||
self.layer.cornerRadius = frame.size.height * 0.5
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user