{"id":710,"date":"2020-08-15T18:25:52","date_gmt":"2020-08-15T10:25:52","guid":{"rendered":"http:\/\/123.57.164.21\/?p=710"},"modified":"2020-08-15T21:25:28","modified_gmt":"2020-08-15T13:25:28","slug":"swiftui%e5%8a%a8%e7%94%bb2-geometryeffect","status":"publish","type":"post","link":"https:\/\/92it.top\/?p=710","title":{"rendered":"SwiftUI\u52a8\u753b(2) GeometryEffect"},"content":{"rendered":"\n<p>\u5728\u7b2c\u4e00\u90e8\u5206\u4ecb\u7ecd\u4e86<code><span class=\"has-inline-color has-vivid-red-color\">Animatable<\/span><\/code>\u534f\u8bae\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u4e3aPath\u8bbe\u7f6e\u52a8\u753b\u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5c06\u4f7f\u7528\u65b0\u7684\u5de5\u5177<span class=\"has-inline-color has-vivid-red-color\">GeometryEffect<\/span>\u3002<\/p>\n\n\n\n<p><code>GeometryEffect<\/code>\u5b9e\u73b0\u4e86<code>Animatable<\/code>\u548c<code>ViewModifier<\/code>\u8fd9\u4e24\u4e2a\u534f\u8bae\uff0c\u56e0\u6b64\u8bf4\u660e\u5b83\u81ea\u8eab\u5c31\u80fd\u5b9e\u73b0\u52a8\u753b\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u901a\u8fc7<code>modifier<\/code>\u6765\u5199\u4ee3\u7801\u3002<\/p>\n\n\n\n<p>\u5927\u5bb6\u53ef\u80fd\u6bd4\u8f83\u7591\u60d1\uff0c<code>GeometryEffect<\/code>\u5728\u54ea\u91cc\u7528\u5230\u4e86\u5462\uff1f\u5176\u5b9e\u7528\u5230\u7684\u5730\u65b9\u5f88\u591a\uff0c\u6bd4\u5982\u7cfb\u7edf\u4e2d\u7684<code>offset<\/code>\u5c31\u53ef\u4ee5\u7528\u5176\u5b9e\u73b0\uff0c\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public extension View {\n    func offset(x: CGFloat, y: CGFloat) -> some View {\n        return modifier(_OffsetEffect(offset: CGSize(width: x, height: y)))\n    }\n\n    func offset(_ offset: CGSize) -> some View {\n        return modifier(_OffsetEffect(offset: offset))\n    }\n}\n\nstruct _OffsetEffect: GeometryEffect {\n    var offset: CGSize\n    \n    var animatableData: CGSize.AnimatableData {\n        get { CGSize.AnimatableData(offset.width, offset.height) }\n        set { offset = CGSize(width: newValue.first, height: newValue.second) }\n    }\n\n    public func effectValue(size: CGSize) -> ProjectionTransform {\n        return ProjectionTransform(CGAffineTransform(translationX: offset.width, y: offset.height))\n    }\n}<\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Animation Keyframes<\/h4>\n\n\n\n<p>SwiftUI\u5e76\u6ca1\u6709\u76f4\u63a5\u63d0\u4f9b\u5173\u952e\u5e27\u52a8\u753b\u76f8\u5173\u7684modifier\uff0c\u4f46\u6211\u4eec\u5b8c\u5168\u53ef\u4ee5\u7528<code>GeometryEffect<\/code>\u6765\u5b9e\u73b0\uff0c\u4f46\u662f\u5728\u8fd9\u4ee5\u524d\uff0c\u6211\u4eec\u5148\u4ecb\u7ecd\u4e00\u4e2a\u5173\u4e8eview\u5f62\u53d8\u7684\u76f8\u5173\u7684\u4e00\u4e2a\u6838\u5fc3\u5185\u5bb9<code>CGAffineTransform<\/code><\/p>\n\n\n\n<p>\u5b66\u8fc7\u7ebf\u6027\u4ee3\u6570\u7684\u540c\u5b66\u4e00\u5b9a\u660e\u767d\uff0c\u6240\u8c13\u7684\u5f62\u53d8\u672c\u8d28\u4e0a\u5c31\u662f\u628a\u4e00\u4e9b\u70b9\u7684\u96c6\u5408\u901a\u8fc7\u4e00\u4e2a\u5f62\u53d8\u77e9\u9635\u6620\u5c04\u6210\u53e6\u5916\u4e00\u4e2a\u70b9\u96c6\u3002\u8fd9\u91cc\u8fb9\u8bbe\u8ba1\u5230\u4e86\u77e9\u9635\u7684\u4e58\u6cd5\u3002<\/p>\n\n\n\n<p>\u5f62\u53d8\u7684\u4e3b\u8981\u5185\u5bb9\u6709\uff1a<\/p>\n\n\n\n<ul><li>\u5e73\u79fb<\/li><li>\u7f29\u653e<\/li><li>\u65cb\u8f6c<\/li><\/ul>\n\n\n\n<p>\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u770b\u4e0b\u56fe\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"495\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/1914952-39a39cc8e1efdc74.png\" alt=\"\" class=\"wp-image-713\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-39a39cc8e1efdc74.png 675w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-39a39cc8e1efdc74-300x220.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-39a39cc8e1efdc74-230x169.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-39a39cc8e1efdc74-350x257.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-39a39cc8e1efdc74-480x352.png 480w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure>\n\n\n\n<p>\u7531\u4e8e\u6211\u4eec\u7684\u624b\u673a\u662f\u4e00\u4e2a\u4e8c\u7ef4\u5e73\u9762\uff0cA\uff0810\uff0c 10\uff09\u5e73\u79fb\u5230A\u2018\uff0820\uff0c 20\uff09\u53ea\u9700\u8981\u5206\u522b\u5728x\uff0cy\u8f74\u90fd\u52a0\u4e0a10\u5c31\u53ef\u4ee5\u4e86\uff0c\u7528\u6570\u5b66\u8868\u8fbe\u5f0f\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-66-1024x77.png\" alt=\"\" class=\"wp-image-714\" width=\"580\" height=\"43\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-1024x77.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-300x22.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-768x58.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-830x62.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-230x17.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-350x26.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66-480x36.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-66.png 1388w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/><\/figure><\/div>\n\n\n\n<p>\u4e5f\u5c31\u662f\u8bf4\u5e73\u79fb\u7b97\u6cd5\u5176\u5b9e\u5c31\u662f\u77e9\u9635\u7684\u52a0\u6cd5\uff0c\u5982\u679c\u53ea\u8003\u8651\u5e73\u79fb\uff0c\u6211\u4eec\u7528\u4e00\u4e2a\u4e8c\u7ef4\u5411\u91cf\u5c31\u53ef\u4ee5\u8868\u793a\uff0c\u6211\u4eec\u7ee7\u7eed\u5f80\u4e0b\u770b\u7f29\u653e\u7684\u4f8b\u5b50\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"482\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/1914952-dbbba07067579b73-1.png\" alt=\"\" class=\"wp-image-716\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-dbbba07067579b73-1.png 626w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-dbbba07067579b73-1-300x231.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-dbbba07067579b73-1-230x177.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-dbbba07067579b73-1-350x269.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-dbbba07067579b73-1-480x370.png 480w\" sizes=\"(max-width: 626px) 100vw, 626px\" \/><\/figure><\/div>\n\n\n\n<p>\u6211\u4eec\u5148\u89c4\u5b9a\u4e00\u5f00\u59cb\u7684\u77e9\u5f62\u6ca1\u6709\u7f29\u653e\u64cd\u4f5c\uff0c\u6211\u4eec\u628a\u77e9\u5f62\u653e\u59273\u500d\uff0c\u672c\u8d28\u4e0a\u5c31\u76f8\u5f53\u4e8e\u5bf9\u5355\u4f4d\u77e9\u9635\u8fdb\u884c\u7f29\u653e\uff0c\u7136\u540e\u5728\u4e58\u4ee5\u7f29\u653e\u540e\u7684\u5355\u4f4d\u77e9\u9635<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"296\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-69-1024x296.png\" alt=\"\" class=\"wp-image-727\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-1024x296.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-300x87.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-768x222.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-830x240.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-230x67.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-350x101.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69-480x139.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-69.png 1210w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>\u540c\u7406\uff0c\u65cb\u8f6c\u4e5f\u53ef\u4ee5\u7406\u89e3\u4e3a\u5148\u5bf9\u5355\u4f4d\u77e9\u9635\u8fdb\u884c\u65cb\u8f6c:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"488\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-68-1024x488.png\" alt=\"\" class=\"wp-image-720\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-1024x488.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-300x143.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-768x366.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-830x395.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-230x110.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-350x167.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68-480x229.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-68.png 1340w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>\u6211\u4eec\u53ef\u4ee5\u6839\u636e\u516c\u5f0f\u63a8\u7b97\u51fax\u2019\uff0cy&#8217;\u7684\u503c\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"184\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-70-1024x184.png\" alt=\"\" class=\"wp-image-728\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-1024x184.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-300x54.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-768x138.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-830x149.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-230x41.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-350x63.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70-480x86.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-70.png 1268w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\u73b0\u5728\u5df2\u7ecf\u975e\u5e38\u660e\u663e\u4e86\uff0c\u7528\u4e00\u70b9\u7ebf\u6027\u4ee3\u6570\u7684\u77e5\u8bc6\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u63a8\u5bfc\u51fa\u65cb\u8f6c\u77e9\u9635\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"125\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-71-1024x125.png\" alt=\"\" class=\"wp-image-729\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-1024x125.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-300x37.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-768x94.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-830x102.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-230x28.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-350x43.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71-480x59.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-71.png 1292w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\u56e0\u6b64\uff0c\u65cb\u8f6c\u77e9\u9635\u4e3a\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"111\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-72-1024x111.png\" alt=\"\" class=\"wp-image-730\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-1024x111.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-300x33.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-768x83.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-830x90.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-230x25.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-350x38.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72-480x52.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-72.png 1288w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\u6ce8\u610f\uff0c\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u8ba8\u8bba\u7684\u53ea\u662f<strong>\u4e8c\u7ef4\u5e73\u9762\u4e0a\u7684\u5f62\u53d8<\/strong>\uff0c\u81f3\u4e8e\u4e09\u7ef4\u7684\uff0c\u4e5f\u53ef\u4ee5\u6839\u636e\u8fd9\u5957\u65b9\u6cd5\u63a8\u5bfc\u51fa\uff0c\u5728\u8fd9\u91cc\u5c31\u4e0d\u505a\u66f4\u591a\u7684\u89e3\u91ca\u4e86\u3002<\/p>\n\n\n\n<p>\u76f8\u4fe1\u5927\u5bb6\u4e00\u5b9a\u6709\u4e2a\u7591\u95ee\uff1f\u4f4d\u79fb\u7528\u77e9\u9635\u52a0\u6cd5\uff0c\u7f29\u653e\u548c\u65cb\u8f6c\u7528\u77e9\u9635\u4e58\u6cd5\uff0c\u80fd\u5426\u8fd93\u4e2a\u5f62\u53d8\u90fd\u4f7f\u7528\u540c\u4e00\u4e2a\u8fd0\u7b97\u5462\uff1f\u7b54\u6848\u662f\u6709\u7684\uff0c\u5982\u679c\u6ca1\u6709\u7ebf\u6027\u4ee3\u6570\u7684\u77e5\u8bc6\uff0c\u7406\u89e3\u8d77\u6765\u5c31\u4f1a\u6bd4\u8f83\u56f0\u96be\u3002<\/p>\n\n\n\n<p>\u6211\u4eec\u628a2\u7ef4\u7684\u70b9\u5347\u7ef4\u52303\u7ef4\uff0c\u5927\u5bb6\u53ef\u4ee5\u60f3\u8c61x\uff0cy\u8f74\u5904\u4e8e\u5c4f\u5e55\u4e0a\uff0c\u65b0\u589e\u4e00\u4e2az\u8f74\uff0c\u7531\u5c4f\u5e55\u6307\u5411\u6211\u4eec\u5934\u90e8\uff0c\u539f\u6765\u6211\u4eec\u7684\u70b9\u90fd\u5728\u5c4f\u5e55\u4e0a\uff0c\u4e5f\u5c31\u662fz\u90fd\u4e3a0\uff0c\u6211\u4eec\u73b0\u5728\u4f7f\u7528z=1\u7684\u5e73\u9762\uff0c\u8fd9\u4e2a\u5e73\u9762\u4e0e\u5c4f\u5e55\u5e73\u884c\uff0c\u4e8e\u662f\u6211\u4eec\u5f97\u5230\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"269\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-76-1024x269.png\" alt=\"\" class=\"wp-image-734\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-1024x269.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-300x79.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-768x202.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-830x218.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-230x60.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-350x92.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76-480x126.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-76.png 1354w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\u6211\u4eec\u4ed4\u7ec6\u89c2\u5bdf\u4e0a\u8fb9\u7684\u516c\u5f0f\uff0c\u53ef\u4ee5\u53d1\u73b0\u8fd9\u6837\u7684\u5bf9\u5e94\u5173\u7cfb\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"99\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-74-1024x99.png\" alt=\"\" class=\"wp-image-732\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-1024x99.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-300x29.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-768x74.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-830x80.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-230x22.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-350x34.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74-480x46.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-74.png 1202w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>\u603b\u7ed3\u4e00\u4e0b\uff1a<\/p>\n\n\n\n<ul><li>\u53ea\u8003\u7387\u4f4d\u79fb\uff1ax\u53ea\u9700\u8981\u8bbe\u7f6ee\uff0cabcdf\u90fd\u4e3a0\uff0ctx\uff1by\u53ea\u9700\u8981\u8bbe\u7f6ef\uff0cabcde\u90fd\u4e3a0<\/li><li>\u53ea\u8003\u7387\u7f29\u653e\uff1ax\u53ea\u9700\u8981\u8bbe\u7f6ea\uff0cbcdef\u90fd\u4e3a0\uff0csx\uff1by\u53ea\u9700\u8981\u8bbe\u7f6ed\uff0cabcef\u90fd\u4e3a0<\/li><li>\u53ea\u8003\u7387\u65cb\u8f6c\uff1ax\u53ea\u9700\u8981\u8bbe\u7f6ea\uff0cc\uff0cbdef\u90fd\u4e3a0\uff0cy\u53ea\u9700\u8981\u8bbe\u7f6eb,d\uff0cabcef\u90fd\u4e3a0<\/li><\/ul>\n\n\n\n<p>\u597d\u7684\uff0c\u5230\u76ee\u524d\u6211\u4e3a\u6b62\uff0c\u6211\u4eec\u5df2\u7ecf\u7edf\u4e00\u4e86\u5f62\u53d8\u7684\u64cd\u4f5c\u3002\u90fd\u53ef\u4ee5\u7528\u77e9\u9635\u4e58\u6cd5\u6765\u5b9e\u73b0\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"277\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-75-1024x277.png\" alt=\"\" class=\"wp-image-733\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-1024x277.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-300x81.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-768x207.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-830x224.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-230x62.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-350x95.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75-480x130.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-75.png 1214w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>\u56de\u8fc7\u5934\u6765\uff0c\u6211\u4eec\u518d\u770b\u4e0b\u8fb9\u8fd9\u6bb5\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    func effectValue(size: CGSize) -> ProjectionTransform {\n        return ProjectionTransform(CGAffineTransform(a: 1, b: 0, c: skew, d: 1, tx: offset, ty: 0))\n    }\n<\/pre>\n\n\n\n<p>\u518d\u56de\u770b\u516c\u5f0f11\uff0c\u5c31\u4e0d\u96be\u7406\u89e3\uff0c\u5728x\u4f4d\u79fboffset\u7684\u60c5\u51b5\u4e0b\uff0cx\u8fd8\u8981\u503e\u659cyc\u7684\u8ddd\u79bb\uff0c\u4e5f\u5c31\u662fx\u4f1a\u968f\u7740\u4e0d\u540c\u7684y\u6709\u4e00\u5b9a\u7684\u503e\u659c\u89d2\u5ea6\uff0c\u5982\u4e0b\u56fe\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"255\" height=\"181\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/1914952-375d6d24c86d9a28.png\" alt=\"\" class=\"wp-image-735\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-375d6d24c86d9a28.png 255w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/1914952-375d6d24c86d9a28-230x163.png 230w\" sizes=\"(max-width: 255px) 100vw, 255px\" \/><\/figure><\/div>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Animation Feedback<\/h4>\n\n\n\n<p>\u52a8\u753b\u53cd\u9988\u7684\u610f\u601d\u6307\u7684\u662f\u52a8\u753b\u5728\u8fdb\u884c\u4e2d\uff0c\u6211\u4eec\u76d1\u542c\u52a8\u753b\u5f53\u524d\u6267\u884c\u7684\u53c2\u6570\uff0c\u7136\u540e\u6839\u636e\u8fd9\u4e9b\u53c2\u6570\u53bb\u505a\u4e00\u4e9b\u5176\u4ed6\u7684\u4e8b\u60c5\u3002<\/p>\n\n\n\n<p>\u8fd9\u53e5\u8bdd\u4e0d\u592a\u597d\u7406\u89e3\uff0c\u4e3e\u4e2a\u4f8b\u5b50\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"457\" height=\"450\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/1914952-c0a4173d7a5548d8.gif\" alt=\"\" class=\"wp-image-736\"\/><\/figure><\/div>\n\n\n\n<p>\u4e0a\u56fe\u4e2d\u5361\u7247\u6709\u4e24\u79cd\u65cb\u8f6c\uff1a<\/p>\n\n\n\n<ul><li>360\u65cb\u8f6c<\/li><li>\u5361\u7247\u6cbf\u7740\u67d0\u4e2a\u8f74360\u5ea6\u65cb\u8f6c<\/li><\/ul>\n\n\n\n<p>\u5f53\u5361\u7247\u6cbf\u7740\u67d0\u4e2a\u8f74360\u65cb\u8f6c\u7684\u65f6\u5019\uff0c \u6211\u4eec\u53ef\u4ee5\u518d<code>effectValue<\/code>\u4e2d\u76d1\u542c\u5230\u52a8\u753b\u5f53\u524d\u65cb\u8f6c\u7684\u89d2\u5ea6\uff0c\u6839\u636e\u5f53\u524d\u7684\u8fd9\u4e2a\u89d2\u5ea6\u6211\u4eec\u4e3b\u52a8\u7684\u63a7\u5236\u56fe\u7247\u7684\u5185\u5bb9\uff0c\u5728\u672c\u4f8b\u4e2d\uff0c\u5f53\u89d2\u5ea6\u5904\u4e8e90~270\u4e4b\u95f4\u65f6\uff0c\u663e\u793a\u80cc\u9762\u7684\u56fe\u7247\u3002\u4e00\u65e6\u6211\u4eec\u76d1\u542c\u5230\u65cb\u8f6c\u7684\u89d2\u5ea6\u8fbe\u523090\u6216\u8005270\u7684\u65f6\u5019\uff0c\u6211\u4eec\u66ff\u6362\u663e\u793a\u7684\u56fe\u7247\u3002<\/p>\n\n\n\n<p>\u8fd9\u91cc\u7684\u91cd\u70b9\u662f\uff0c\u6211\u4eec\u80fd\u591f\u5728<code>effectValue<\/code>\u4e2d\u76d1\u542c\u5230\u5f53\u524d\u52a8\u753b\u7684\u72b6\u6001\uff0c\u7136\u540e\u57fa\u4e8e\u6b64\u72b6\u6001\u505a\u989d\u5916\u7684\u903b\u8f91\u3002<\/p>\n\n\n\n<p>\u90a3\u4e48\u6211\u4eec\u662f\u5982\u4f55\u505a\u5230\u7684\u5462\uff1f\u6838\u5fc3\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct FlipEffect: GeometryEffect {\n    @Binding var flipped: Bool\n    var angle: Double\n    let axis: (CGFloat, CGFloat)\n    \n    var animatableData: Double {\n        get {\n            angle\n        }\n        set {\n            angle = newValue\n        }\n    }\n    \n    func effectValue(size: CGSize) -> ProjectionTransform {\n        DispatchQueue.main.async {\n            self.flipped = (self.angle >= 90 &amp;&amp; self.angle &lt; 270)\n        }\n        \n        let a = CGFloat(Angle.degrees(angle).radians)\n        \n        var  transform3d = CATransform3DIdentity\n        transform3d.m34 = -1\/max(size.width, size.height)\n        transform3d = CATransform3DRotate(transform3d, a, self.axis.0, self.axis.1, 0)\n        transform3d = CATransform3DTranslate(transform3d, -size.width\/2.0, -size.height\/2.0, 0)\n        \n        let affineTransform = ProjectionTransform(CGAffineTransform(translationX: size.width\/2.0, y: size.height\/2.0))\n        \n        return ProjectionTransform(transform3d).concatenating(affineTransform)\n    }\n}<\/pre>\n\n\n\n<p>\u7531\u4e8eGeometryEffect\u5b9e\u73b0\u4e86Animatable\u534f\u8bae\uff0c\u7cfb\u7edf\u4f1a\u6839\u636e<code>animatableData<\/code>\u6765\u52a8\u6001\u7684\u8ba1\u7b97\u53c2\u6570\uff0c\u8fd9\u91cc\u9700\u8981\u8ba1\u7b97\u7684\u53c2\u6570\u6307\u7684\u662f<code>angle<\/code>\u3002<code>angle<\/code>\u4f1a\u88ab\u6253\u6563\u6210\u5f88\u591a\u4e0d\u540c\u7684\u6570\u5b57\uff0c\u7cfb\u7edf\u4f1a\u9488\u5bf9\u6bcf\u4e00\u4e2a\u4e0d\u540c\u7684<code>angle<\/code>\u90fd\u8c03\u7528<code>effectValue<\/code>\u65b9\u6cd5\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DispatchQueue.main.async {\n            self.flipped = (self.angle >= 90 &amp;&amp; self.angle &lt; 270)\n        }\n<\/pre>\n\n\n\n<p>\u6211\u4eec\u6839\u636e\u5f53\u524d\u7684\u89d2\u5ea6\u6765\u51b3\u5b9a<code>flipped<\/code>\u7684\u503c\uff0c\u56e0\u6b64<code>flipped<\/code>\u662f\u9891\u7e41\u88ab\u8d4b\u503c\u7684\u3002<strong>\u6211\u4eec\u5f97\u51fa\u7684\u7ed3\u8bba\u662f\uff1a\u7cfb\u7edf\u6839\u636e\u52a8\u753b\u51fd\u6570\u8ba1\u7b97angle\uff0c\u7136\u540e\u5728<code>effectValue<\/code>\u4e2d\u83b7\u53d6angle\uff0c\u518d\u6839\u636e\u8fd9\u4e2a\u503c\u5904\u7406\u6211\u4eec\u81ea\u5df1\u7684\u903b\u8f91\u3002<\/strong><\/p>\n\n\n\n<p><code>angle<\/code>\u662f\u4e00\u4e2aBinding\u7684\u503c\uff1a<code>@Binding var flipped: Bool<\/code>\uff0c\u5b83\u7684\u503c\u7684\u6539\u53d8\u4f1a\u5f80\u4e0a\u5c42\u629b\u51fa\uff0c\u6211\u4eec\u518d\u770b\u770b\u4e0b\u8fb9\u7684\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct RotatingCard: View {\n    @State private var flipped = false\n    @State private var animate3d = false\n    @State private var rotate = false\n    @State private var imgIndex = 0\n    \n    let images = [\"1\", \"2\", \"3\", \"4\", \"5\"]\n    \n    var body: some View {\n        let binding = Binding&lt;Bool>(get: { self.flipped }, set: { self.updateBinding($0) })\n        \n        return VStack {\n            Spacer()\n            Image(flipped ? \"bg\" : images[imgIndex]).resizable()\n                .frame(width: 212, height: 320)\n                .modifier(FlipEffect(flipped: binding, angle: animate3d ? 360 : 0, axis: (x: 1, y: 5)))\n                .rotationEffect(Angle(degrees: rotate ? 0 : 360))\n                .onAppear {\n                    withAnimation(Animation.linear(duration: 4.0).repeatForever(autoreverses: false)) {\n                        self.animate3d = true\n                    }\n                    \n                    withAnimation(Animation.linear(duration: 8.0).repeatForever(autoreverses: false)) {\n                        self.rotate = true\n                    }\n            }\n            Spacer()\n        }\n    }\n    \n    func updateBinding(_ value: Bool) {\n        \/\/ If card was just flipped and at front, change the card\n        if flipped != value &amp;&amp; !flipped {\n            self.imgIndex = self.imgIndex+1 &lt; self.images.count ? self.imgIndex+1 : 0\n        }\n        \n        flipped = value\n    }\n}<\/pre>\n\n\n\n<p>\u53ef\u4ee5\u770b\u51fa\uff0c\u4f9d\u8d56<code>flipped<\/code>\u5728\u4e34\u754c\u70b9\u7684\u53d8\u5316\uff0c\u6211\u4eec\u5207\u6362<code>iamgeIndex<\/code>,\u4ece\u800c\u5b9e\u73b0\u4e86\u5207\u6362\u663e\u793a\u56fe\u7247\u7684\u76ee\u7684\u3002<\/p>\n\n\n\n<p>\u8fd9\u4e00\u5c0f\u7ed3\u7684\u76ee\u7684\u662f\u8ba9\u6211\u4eec\u77e5\u9053\uff0c\u53ef\u4ee5\u5728<code>effectValue<\/code>\u4e2d\u83b7\u5f97\u52a8\u753b\u72b6\u6001\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Make a View Follow a Path<\/h4>\n\n\n\n<p>\u8fd9\u4e00\u5c0f\u8282\u7684\u6311\u6218\u662f\u8ba9\u67d0\u4e00\u4e2aview\u6cbf\u7740\u67d0\u4e2apath\u8fd0\u52a8\uff0c\u5bf9\u4e8e\u6bd4\u8f83\u7b80\u5355\u7684\u56fe\u5f62\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528AnimatableData\u6765\u5b9e\u73b0\uff0c\u6bd4\u65b9\u8bf4\u8ba9\u5c0f\u7403\u6cbf\u7740\u5706\u73af\u8fd0\u52a8\uff0c\u901a\u8fc7\u8ba1\u7b97\u65cb\u8f6c\u7684\u89d2\u5ea6\u5c31\u53ef\u4ee5\u5b9e\u73b0\u3002\u4e00\u65e6\u8def\u5f84\u53d8\u5f97\u590d\u6742\uff0c\u6211\u4eec\u5c31\u9047\u5230\u4e86\u6311\u6218\uff0c\u6bd4\u5982\u4e0b\u8fb9\u8fd9\u6837\u7684\u6548\u679c\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"463\" height=\"305\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/1914952-7fa6f42b42323e5b.gif\" alt=\"\" class=\"wp-image-741\"\/><\/figure><\/div>\n\n\n\n<p>\u5f88\u660e\u663e\uff0c\u4e3a\u4e86\u80fd\u591f\u8ba9\u98de\u673a\u6cbf\u7740\u6307\u5b9a\u7684\u8def\u5f84\u8fd0\u52a8\uff0c\u5e76\u4e14\u65b9\u5411\u4fdd\u6301\u4e00\u81f4\uff0c\u9700\u8981\u505a\u5230\u4ee5\u4e0b\u4e24\u70b9\uff1a<br><\/p>\n\n\n\n<ul><li>\u5b9e\u65f6\u8ba1\u7b97\u98de\u673a\u7684\u4f4d\u7f6e<\/li><li>\u8ba1\u7b97\u98de\u673a\u7684\u65cb\u8f6c\u65b9\u5411<\/li><\/ul>\n\n\n\n<p>\u7ed8\u5236path\uff0c\u7528\u5230\u4e86\u8d1d\u585e\u5c14\u66f2\u7ebf\u7684\u77e5\u8bc6\uff0c\u8fd9\u91cc\u5c31\u4e0d\u505a\u8fc7\u591a\u7684\u89e3\u91ca\u4e86\uff0c\u53ea\u8981\u4f60\u60f3\uff0c\u5229\u7528\u8d1d\u585e\u5c14\u66f2\u7ebf\u80fd\u591f\u753b\u51fa\u4efb\u4f55\u8def\u5f84\u3002\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct InfinityShape: Shape {\n    func path(in rect: CGRect) -> Path {\n        InfinityShape.createInfinityShape(in: rect)\n    }\n    \n    static func createInfinityShape(in rect: CGRect) -> Path {\n        let w = rect.width\n        let h = rect.height\n        let quarternW = w \/ 4.0\n        let quarternH = h \/ 4.0\n        \n        var path = Path()\n        \n        path.move(to: CGPoint(x: quarternW, y: quarternH * 3))\n        path.addCurve(to: CGPoint(x: quarternW, y: quarternH), control1: CGPoint(x: 0, y: quarternH * 3), control2: CGPoint(x: 0, y: quarternH))\n        \n        path.move(to: CGPoint(x: quarternW, y: quarternH))\n        path.addCurve(to: CGPoint(x: quarternW * 3, y: quarternH * 3), control1: CGPoint(x: quarternW * 2, y: quarternH), control2: CGPoint(x: quarternW * 2, y: quarternH * 3))\n        \n        path.move(to: CGPoint(x: quarternW * 3, y: quarternH * 3))\n        path.addCurve(to: CGPoint(x: quarternW * 3, y: quarternH), control1: CGPoint(x: w, y: quarternH * 3), control2: CGPoint(x: w, y: quarternH))\n        \n        path.move(to: CGPoint(x: quarternW * 3, y: quarternH))\n        path.addCurve(to: CGPoint(x: quarternW, y: quarternH * 3), control1: CGPoint(x: quarternW * 2, y: quarternH), control2: CGPoint(x: quarternW * 2, y: quarternH * 3))\n        \n        return path\n    }\n}<\/pre>\n\n\n\n<p>\u5927\u5bb6\u770b\u4e0a\u8fb9\u4ee3\u7801\u7684\u65f6\u5019\uff0c\u53ef\u4ee5\u53c2\u8003\u6211\u4e0b\u8fb9\u753b\u7684\u8fd9\u5f20\u56fe\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-77-1024x772.png\" alt=\"\" class=\"wp-image-744\" width=\"511\" height=\"385\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-1024x772.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-300x226.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-768x579.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-830x626.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-230x173.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-350x264.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77-480x362.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-77.png 1326w\" sizes=\"(max-width: 511px) 100vw, 511px\" \/><\/figure><\/div>\n\n\n\n<p>\u6211\u4eec\u9700\u8981\u8ba1\u7b97\u7684\u53c2\u6570\u662f<code>percent<\/code>, \u53d6\u503c\u8303\u56f4\u4e3a0~1\uff0c\u90a3\u4e48\u6211\u4eec\u5982\u4f55\u8ba1\u7b97path\u4e2d\u7684\u5177\u4f53\u7684\u67d0\u4e00\u70b9\u7684Point\u5462\uff1fpath\u63d0\u4f9b\u4e86\u4e00\u4e2a\u65b9\u6cd5\uff1a<code>trimmedPath(from:, to: )<\/code>,\u8be5\u65b9\u6cd5\u4f1a\u8fd4\u56depath\u4e2d\u7684\u67d0\u4e00\u6bb5path\uff0c\u53ea\u8981\u6211\u4eecfrom\u5230to\u7684\u503c\u53d6\u5f97\u8db3\u591f\u5c0f\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u83b7\u53d6\u5230\u6781\u5c0f\u7684\u4e00\u6bb5path\uff0c\u6211\u4eec\u4f7f\u7528\u8be5\u6bb5path\u7684\u4e2d\u5fc3\u4f5c\u4e3aPoint\uff0c\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    \/\/\/ \u8ba1\u7b97\u5f53\u524d\u7684\u70b9\u7684\u4f4d\u7f6e\n    func percentPoint(_ percent: CGFloat) -> CGPoint {\n        let pct = percent > 1 ? 0 : (percent &lt; 0 ? 1 : percent)\n        let f = pct > 0.999 ? 0.999 : pct\n        let t = pct > 0.999 ? 1 : pct + 0.001\n        let tp = path.trimmedPath(from: f, to: t)\n        return CGPoint(x: tp.boundingRect.midX, y: tp.boundingRect.midY)\n    }<\/pre>\n\n\n\n<p>\u7b2c\u4e8c\u4e2a\u6311\u6218\u662f\u5982\u4f55\u83b7\u53d6\u67d0\u4e00\u70b9\u7684\u65cb\u8f6c\u89d2\u5ea6\uff0c\u6709\u4e86\u4e0a\u8fb9\u7684\u7ed3\u679c\uff0c\u6211\u4eec\u5c31\u80fd\u591f\u6839\u636epercent\u83b7\u53d6\u5230\u67d0\u4e2aPoint\uff0c\u5047\u8bbe\u6211\u4eec\u60f3\u83b7\u53d6\u67d0\u4e00\u70b9P\u7684\u65b9\u5411\uff0c\u6211\u4eec\u53ef\u4ee5\u6839\u636eP\u5bf9\u5e94\u7684\uff08percent &#8211; 0.001\uff09\u6765\u83b7\u53d6P\u7684\u524d\u4e00\u4e2a\u70b9\uff0c\u6709\u4e86\u4e24\u4e2a\u70b9\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u8ba1\u7b97\u65b9\u5411\u4e86\u3002\u5148\u770b\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    \/\/\/ \u8ba1\u7b97\u4e24\u70b9\u89d2\u5ea6\n    func calculateDirection(_ pt1: CGPoint, _ pt2: CGPoint) -> CGFloat {\n        let a = pt2.x - pt1.x\n        let b = pt2.y - pt1.y\n        \n        let angle = (a > 0) ? atan(b \/ a) : atan(b \/ a) - CGFloat.pi\n        \n        return angle\n    }\n<\/pre>\n\n\n\n<p>\u8fd9\u91cc\u8bb2\u89e3\u4ee5\u4e0b<code>let angle = (a &gt; 0) ? atan(b \/ a) : atan(b \/ a) - CGFloat.pi<\/code>\u8fd9\u4e00\u884c\u4ee3\u7801\u7684\u610f\u4e49\uff0c\u5148\u770b\u4e0b\u56fe\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/image-78-1009x1024.png\" alt=\"\" class=\"wp-image-745\" width=\"474\" height=\"481\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-1009x1024.png 1009w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-296x300.png 296w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-768x780.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-830x843.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-230x233.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-350x355.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78-480x487.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2020\/08\/image-78.png 1322w\" sizes=\"(max-width: 474px) 100vw, 474px\" \/><\/figure><\/div>\n\n\n\n<p>\u6211\u4eec\u5047\u8bbeP0\u4e3a\u524d\u4e00\u4e2a\u70b9\uff0cP1\uff0cP2, P3, P4\u5206\u522b\u4e3a\u9700\u8981\u8ba1\u7b97\u7684\u70b9\uff0c\u5728\u4e00\u4e2a\u5e73\u9762\u4e2d\uff0c\u65b9\u5411\u6700\u591a\u5b58\u5728\u8fd94\u4e2a\u65b9\u5411\uff0c\u5206\u522b\u4f4d\u4e8e\u4e0d\u540c\u7684\u8c61\u9650\u4e2d\u3002<\/p>\n\n\n\n<p><strong>\u6ce8\u610f\uff0c\u5728iOS\u4e2d\uff0cy\u662f\u8d8a\u5f80\u4e0b\u8d8a\u5927\u7684\u3002\u89d2\u5ea6\u662f\u6309\u7167\u987a\u65f6\u9488\u7b97\u7684\uff0c\u4e0a\u56fe\u4e2d\u7684\u89d21\u662f\u8d1f\u7684\uff0c\u89d22\u624d\u662f\u6b63\u7684\u3002<\/strong><\/p>\n\n\n\n<p>\u5173\u4e8eatan(),  \u4e3e\u4e2a\u4f8b\u5b50\u5047\u8bbeatan(x) = 1.5, \u90a3\u4e48atan(-x) = -1.5\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">        let a = pt2.x - pt1.x\n        let b = pt2.y - pt1.y\n<\/pre>\n\n\n\n<ul><li>P0 -&gt; P1: a &gt; 0 b &lt; 0 atan(b\/a)\u8ba1\u7b97\u7684\u7ed3\u679c\u662f\u8d1f\u7684\uff0c\u6b63\u597d\u662f\u89d21<\/li><li>P0 -&gt; P2: a &gt; 0 b &gt; 0 atan(b\/a)\u8ba1\u7b97\u7684\u7ed3\u679c\u662f\u6b63\u7684\uff0c\u6b63\u597d\u662f\u89d22<\/li><li>P0 -&gt; P3: a &lt; 0 b &gt; 0 atan(b\/a)\u8ba1\u7b97\u7684\u7ed3\u679c\u662f\u8d1f\u7684\uff0c\u7ed3\u679c\u662f\u89d21\uff0c\u8fd9\u65f6\u5019\u4e3a\u4e86\u83b7\u53d6P0 -&gt; P3\u7684\u89d2\u5ea6\uff0c\u9700\u8981\u518d\u51cf\u53bb180\u5ea6\uff0c\u4e5f\u5c31\u662fpi<\/li><li>P0 -&gt; P4: a &lt; 0 b &lt; 0 atan(b\/a)\u8ba1\u7b97\u7684\u7ed3\u679c\u662f\u6b63\u7684\uff0c\u7ed3\u679c\u662f\u89d22\uff0c\u8fd9\u65f6\u5019\u4e3a\u4e86\u83b7\u53d6P0 -&gt; P4\u7684\u89d2\u5ea6\uff0c\u9700\u8981\u518d\u51cf\u53bb180\u5ea6\uff0c\u4e5f\u5c31\u662fpi<\/li><\/ul>\n\n\n\n<p>\u4e0d\u96be\u53d1\u73b0\uff0c\u5982\u679ca&gt;0,  \u90a3\u4e48\u8ba1\u7b97\u7684\u7ed3\u679c\u6b63\u597d\u662f\u6211\u4eec\u60f3\u8981\u7684\u89d2\u5ea6\uff0c\u5176\u4ed6\u60c5\u51b5\u5219\u9700\u8981\u5728\u7ed3\u679c\u7684\u57fa\u7840\u4e0a\u518d\u51cf\u53bb180\u5ea6\uff0c\u73b0\u5728\u5927\u5bb6\u5e94\u8be5\u660e\u767d\u4e0a\u8fb9\u7684\u4ee3\u7801\u4e86\u5427\uff1f<\/p>\n\n\n\n<p>\u5b8c\u6574\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct FollowEffect: GeometryEffect {\n    var pct: CGFloat\n    let path: Path\n    \n    var animatableData: CGFloat {\n        get {\n            pct\n        }\n        set {\n            pct = newValue\n        }\n    }\n    \n    func effectValue(size: CGSize) -> ProjectionTransform {\n        let pt1 = percentPoint(pct - 0.01)\n        let pt2 = percentPoint(pct)\n        \n        let angle = calculateDirection(pt1, pt2)\n        let transform = CGAffineTransform(translationX: pt1.x, y: pt1.y).rotated(by: angle)\n        \n        return ProjectionTransform(transform)\n    }\n    \n    \/\/\/ \u8ba1\u7b97\u4e24\u70b9\u89d2\u5ea6\n    func calculateDirection(_ pt1: CGPoint, _ pt2: CGPoint) -> CGFloat {\n        let a = pt2.x - pt1.x\n        let b = pt2.y - pt1.y\n        \n        let angle = (a > 0) ? atan(b \/ a) : atan(b \/ a) - CGFloat.pi\n        \n        return angle\n    }\n    \n    \/\/\/ \u8ba1\u7b97\u5f53\u524d\u7684\u70b9\u7684\u4f4d\u7f6e\n    func percentPoint(_ percent: CGFloat) -> CGPoint {\n        let pct = percent > 1 ? 0 : (percent &lt; 0 ? 1 : percent)\n        let f = pct > 0.999 ? 0.999 : pct\n        let t = pct > 0.999 ? 1 : pct + 0.001\n        let tp = path.trimmedPath(from: f, to: t)\n        return CGPoint(x: tp.boundingRect.midX, y: tp.boundingRect.midY)\n    }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct Example9: View {\n    @State private var flag = false\n    \n    var body: some View {\n        GeometryReader { proxy in\n            ZStack(alignment: .topLeading) {\n                InfinityShape().stroke(Color.green, style: StrokeStyle(lineWidth: 4, lineCap: .round, lineJoin: .miter, miterLimit: 0, dash: [7, 7], dashPhase: 0))\n                    .frame(width: proxy.size.width, height: 300)\n                \n                \/\/ Animate movement of Image\n                Image(systemName: \"airplane\").resizable().foregroundColor(Color.red)\n                    .frame(width: 50, height: 50).offset(x: -25, y: -25)\n                    .modifier(FollowEffect(pct: self.flag ? 1 : 0, path: InfinityShape.createInfinityShape(in: CGRect(x: 0, y: 0, width: proxy.size.width, height: 300))))\n                    .onAppear {\n                        withAnimation(Animation.linear(duration: 4.0).repeatForever(autoreverses: false)) {\n                            self.flag.toggle()\n                        }\n                    }\n\n                }.frame(alignment: .topLeading)\n            }\n            .padding(20)\n        }\n}<\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Ignored By Layout<\/h4>\n\n\n\n<p>\u4ec0\u4e48\u53ebIgnored By Layout\u5462\uff1f\u5176\u5b9e\u8fd9\u4e2a\u6982\u5ff5\u5728\u7279\u5b9a\u7684\u573a\u666f\u4e0b\u5f88\u6709\u7528\u3002\u6211\u4eec\u5148\u770b\u4e2a\u6f14\u793a\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"441\" height=\"194\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2020\/08\/1914952-d2471f60a7924e9a.gif\" alt=\"\" class=\"wp-image-748\"\/><\/figure><\/div>\n\n\n\n<p>\u53ef\u4ee5\u770b\u51fa\uff0c\u7eff\u8272\u957f\u65b9\u5757\u968f\u7740\u52a8\u753b\u7684\u53d8\u5316\uff0c\u5b83\u7684\u5e03\u5c40\u4fe1\u606f\u4e5f\u5728\u4e0d\u65ad\u53d8\u5316\uff0c\u800c\u4e0b\u8fb9\u6a59\u8272\u7684\u957f\u65b9\u5757\u5219\u5e03\u5c40\u4fe1\u606f\u4e0d\u4f1a\u53d8\u5316\uff0c\u5f53\u7136\uff0c\u867d\u7136\u5b83\u7684\u5e03\u5c40\u4fe1\u606f\u5728\u5b9e\u65f6\u7684\u53d8\u5316\uff0c\u540e\u8fb9\u7684\u84dd\u8272\u957f\u65b9\u5757\u4e5f\u4e0d\u4f1a\u81ea\u52a8\u8ddf\u968f\u8fd9\u4e9b\u53d8\u5316\u3002<\/p>\n\n\n\n<p>\u6838\u5fc3\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct IgnoredByLayoutView: View {\n    @State private var animate = false\n    @State private var w: CGFloat = 50\n    \n    var body: some View {\n        VStack {\n            HStack {\n                RoundedRectangle(cornerRadius: 5)\n                    .foregroundColor(.green)\n                    .frame(width: 200, height: 40)\n                    .overlay(ShowSize())\n                    .modifier(MyEffect(x: animate ? -10 : 10))\n                \n                RoundedRectangle(cornerRadius: 5)\n                    .foregroundColor(.blue)\n                    .frame(width: w, height: 40)\n            }\n            \n            HStack {\n                RoundedRectangle(cornerRadius: 5)\n                    .foregroundColor(.orange)\n                    .frame(width: 200, height: 40)\n                    .overlay(ShowSize())\n                    .modifier(MyEffect(x: animate ? -10 : 10).ignoredByLayout())\n                \n                RoundedRectangle(cornerRadius: 5)\n                    .foregroundColor(.red)\n                    .frame(width: w, height: 40)\n            }\n        }\n        .onAppear {\n            withAnimation(Animation.easeInOut(duration: 1.0).repeatForever()) {\n                self.animate = true\n            }\n        }\n    }\n}\n\nstruct MyEffect: GeometryEffect {\n    var x: CGFloat = 0\n    \n    var animatableData: CGFloat {\n        get {\n            x\n        }\n        set {\n            x = newValue\n        }\n    }\n    \n    func effectValue(size: CGSize) -> ProjectionTransform {\n        return ProjectionTransform(CGAffineTransform(translationX: x, y: 0))\n    }\n}\n\nstruct ShowSize: View {\n    var body: some View {\n        GeometryReader { proxy in\n            Text(\"x = \\(proxy.frame(in: .global).minX, specifier: \"%.0f\")\")\n                .foregroundColor(.white)\n        }\n    }\n}<\/pre>\n\n\n\n<p><strong>\u4f7f\u7528<code>.ignoredByLayout()<\/code>,\u53ef\u4ee5\u8ba9\u6211\u4eec\u6709\u80fd\u529b\u5728\u67d0\u4e9b\u7279\u6b8a\u7684\u573a\u666f\u4e0b\uff0c\u4f9d\u7136\u80fd\u591f\u6267\u884c\u52a8\u753b\uff0c\u4f46view\u7684layout\u5e76\u4e0d\u4f1a\u5b9e\u65f6\u8ba1\u7b97\u3002<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">\u603b\u7ed3<\/h4>\n\n\n\n<p><code>GeometryEffect<\/code>\u672c\u8eab\u5df2\u7ecf\u9075\u5b88\u4e86<code>Animatable<\/code>\u534f\u8bae\uff0c\u56e0\u6b64\u6211\u4eec\u9700\u8981\u5728\u81ea\u5b9a\u4e49\u7684effect\u4e2d\u5b9e\u73b0<code>animatableData<\/code>,\u8fd9\u91cc\u8fb9\u7684\u503c\u5c31\u662f\u7cfb\u7edf\u6839\u636e\u52a8\u753b\u8bbe\u7f6e\uff0c\u81ea\u52a8\u8ba1\u7b97\u7684\u503c\uff0c\u6211\u4eec\u4f7f\u7528\u8be5\u503c\uff0c\u5728<code>func effectValue(size: CGSize) -&gt; ProjectionTransform<\/code>\u51fd\u6570\u4e2d\u505a\u4e00\u4e9b\u5fc5\u8981\u7684\u8ba1\u7b97 \u6700\u540e\u8fd4\u56de\u4e00\u4e2a<code>ProjectionTransform<\/code>,\u6765\u544a\u8bc9\u7cfb\u7edfview\u7684\u5f62\u53d8\u4fe1\u606f\u3002<\/p>\n\n\n\n<p>*\u6ce8\uff1a\u4e0a\u8fb9\u7684\u5185\u5bb9\u53c2\u8003\u4e86\u7f51\u7ad9<a rel=\"noreferrer noopener\" href=\"https:\/\/links.jianshu.com\/go?to=https%3A%2F%2Fswiftui-lab.com%2Fswiftui-animations-part2%2F\" target=\"_blank\">https:\/\/swiftui-lab.com\/swiftui-animations-part2\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5728\u7b2c\u4e00\u90e8\u5206\u4ecb\u7ecd\u4e86Animatable\u534f\u8bae\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u4e3aPath\u8bbe\u7f6e\u52a8\u753b\u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5c06\u4f7f\u7528\u65b0\u7684\u5de5\u5177Geome [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/710"}],"collection":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=710"}],"version-history":[{"count":15,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/710\/revisions"}],"predecessor-version":[{"id":802,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/710\/revisions\/802"}],"wp:attachment":[{"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=710"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=710"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=710"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}