From cfb7af2a98bfca324a42af03c785284057eb6639 Mon Sep 17 00:00:00 2001 From: onee Date: Sun, 16 Jul 2023 22:38:44 +0800 Subject: [PATCH 1/9] refactor: add basic settings --- .vscode/settings.json | 3 +++ project/sample-apps/animatingshapes.yml | 1 + project/sample-apps/bubblelevel.yml | 1 + project/sample-apps/recognizinggestures.yml | 1 + project/sample-apps/seismometer.yml | 1 + 5 files changed, 7 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7c2feb7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": false +} diff --git a/project/sample-apps/animatingshapes.yml b/project/sample-apps/animatingshapes.yml index 3ea3f1c..b01c712 100644 --- a/project/sample-apps/animatingshapes.yml +++ b/project/sample-apps/animatingshapes.yml @@ -1,3 +1,4 @@ +# TODO - 内容: 'For each BigDot, you can create a circle view with its offset, color, and scale.' 提示: '' 翻译: '' diff --git a/project/sample-apps/bubblelevel.yml b/project/sample-apps/bubblelevel.yml index 4aab459..b05b8fe 100644 --- a/project/sample-apps/bubblelevel.yml +++ b/project/sample-apps/bubblelevel.yml @@ -1,3 +1,4 @@ +# TODO - 内容: 'This method returns a string describing the value of a Double using a fixed number of digits. You can pass in the number of integer digits and fraction digits you want, or leave those arguments out for the default values of 2.' 提示: '' 翻译: '' diff --git a/project/sample-apps/recognizinggestures.yml b/project/sample-apps/recognizinggestures.yml index a7bad6e..d0e41ee 100644 --- a/project/sample-apps/recognizinggestures.yml +++ b/project/sample-apps/recognizinggestures.yml @@ -1,3 +1,4 @@ +# TODO - 内容: 'Recognizing Gestures' 提示: '' 翻译: '' diff --git a/project/sample-apps/seismometer.yml b/project/sample-apps/seismometer.yml index d32d591..92951f9 100644 --- a/project/sample-apps/seismometer.yml +++ b/project/sample-apps/seismometer.yml @@ -1,3 +1,4 @@ +# TODO - 内容: 'Seismometer' 提示: '' 翻译: '' From d9c7e8d61f946c5203f1ebfb7c2dbbf9d414a787 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 08:50:43 +0800 Subject: [PATCH 2/9] feat: bubble level 50/190 --- project/sample-apps/bubblelevel.yml | 74 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/project/sample-apps/bubblelevel.yml b/project/sample-apps/bubblelevel.yml index b05b8fe..1a463e1 100644 --- a/project/sample-apps/bubblelevel.yml +++ b/project/sample-apps/bubblelevel.yml @@ -13,7 +13,7 @@ 翻译: '' - 内容: 'Because detector is an observable object, any changes to its published values allows SwiftUI to automatically update any views using those values. In this case, you’ll update the bubble’s position.' 提示: '' - 翻译: '' + 翻译: '因为 detector 是一个可观察对象,所以任何对它的 published 值的更改都会使 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,你将更新气泡的位置。' - 内容: 'Bubble Level' 提示: '' 翻译: '' @@ -31,7 +31,7 @@ 翻译: '' - 内容: 'Orientation Data View' 提示: '' - 翻译: '' + 翻译: '朝向数据视图' - 内容: 'Then, use this adjusted value to calculate the roll as a fraction of the entire range of roll values, so that full tilt left is 0.0, flat is 0.5, and full tilt right is 1.0.' 提示: '' 翻译: '' @@ -43,13 +43,13 @@ 翻译: '' - 内容: 'The deviceMotion data may not be there in certain conditions. The way you can tell if the data exists is to try to assign it to a variable or constant using if let. If the motion data exists, it’s assigned to data and the code inside the braces runs. Otherwise, it skips the entire if statement.' 提示: '' - 翻译: '' + 翻译: '在一些情况下,deviceMotion 数据可能不存在。你可以通过 if let 来判断数据是否存在。如果 motion 数据存在,它会被赋值给 data 并且大括号内的代码会被执行。否则,整个 if 语句会被跳过。' - 内容: 'Investigate using an extension on Double to format them in an easy to read way.' 提示: '' 翻译: '' - 内容: 'The timer property stores a Timer instance. A timer waits for a period of time that you specify before running some code. The MotionDetector uses the timer to update its pitch, roll, and zAcceleration values at regular intervals, defined by the updateInterval property.' 提示: '' - 翻译: '' + 翻译: 'timer 这个属性存储了一个 Timer 实例。Timer 会在你指定的时间段之后运行一些代码。MotionDetector 使用 timer 来在 updateInterval 属性定义的时间间隔内更新它的 pitch、roll 和 zAcceleration 值。' - 内容: 'Seismometer' 提示: '' 翻译: '' @@ -58,10 +58,10 @@ 翻译: '' - 内容: 'The OrientationDataView displays the roll and pitch of your iPad as numbers. Roll is the degree of left and right tilt, and pitch is the degree of forward and backward tilt.' 提示: '' - 翻译: '' + 翻译: 'OrientationDataView 会将你的 iPad 的翻滚角和俯仰角以数字的形式显示出来。翻滚角是左右倾斜的角度,俯仰角是前后倾斜的角度。' - 内容: 'This app displays the orientation of your device as numbers and as a graphical version of a bubble level. Try tilting your device and watch the bubble move. Try to make your device level by centering the bubble in the crosshairs. Or place it on a surface like your bedroom floor to determine whether the floor is level.' 提示: '' - 翻译: '' + 翻译: '这个 App 将会分别以数字和可视化的气泡水平仪来显示你设备的方向。你可以尝试倾斜你的设备并观察气泡移动,通过将气泡置于十字准线中心来使设备保持水平。或者将其放在卧室地板等表面上,以确定地板是否水平。' - 内容: 'This property calculates the horizontal placement of the bubble using three steps.' 提示: '' 翻译: '' @@ -73,13 +73,13 @@ 翻译: '' - 内容: 'Welcome to Bubble Level.' 提示: '' - 翻译: '' + 翻译: '欢迎来到“气泡水平仪”这堂课。' - 内容: 'Multiplying the fraction with the size of the level gives you the X position of the bubble.' 提示: '' 翻译: '' - 内容: 'Because detector is an observable object, any changes made to its published values cause SwiftUI to automatically update any views using those values. In this case, changes from the device’s sensors update the Text view with the latest values for the pitch and roll.' 提示: '' - 翻译: '' + 翻译: '因为 detector 是一个可观察对象,所以对它的 published 值所做的任何更改都会导致 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,来自设备传感器的更改会使用最新的俯仰角和翻滚角的值更新 Text 视图上的字符。' - 内容: 'Step 20' 提示: '' 翻译: '' @@ -91,22 +91,22 @@ 翻译: '' - 内容: 'Use the userAcceleration property to get the device’s acceleration after accounting for the downward pull of gravity. If it’s at rest, this number is 0. If it’s accelerating upward, the number is negative, and if it’s accelerating downward, the number is positive.' 提示: '' - 翻译: '' + 翻译: '使用 userAcceleration 属性来获取设备在考虑到重力向下拉的情况下的加速度。如果它处于静止状态,这个数值为 0。如果它向上加速,这个数值为负数,如果它向下加速,这个数值为正数。' - 内容: 'Because all of these calculations are hidden in a property, your view’s body code remains simple and readable.' 提示: '' 翻译: '' - 内容: 'Your device has sensors such as accelerometers and gyroscopes that it uses to sense motion and orientation. The Core Motion framework gives you access to data from these and other sensors.' 提示: '' - 翻译: '' + 翻译: '你的设备有加速计和陀螺仪等传感器,它们用于感知运动和方向。Core Motion 框架可以让你访问这些传感器和其他传感器的数据。' - 内容: 'These two computed properties provide the strings used in the view. They take the roll or pitch value from the motion detector and format that number as a string with a fixed number of digits. The describeAsFixedLengthString() method is a custom method on the Double type. You can learn how it works in DoubleExtension.swift.' 提示: '' - 翻译: '' + 翻译: '这两个计算属性提供了视图中使用的字符串。它们从 motion detector 中获取翻滚角或俯仰角的值,并将该数字格式化为具有固定位数的字符串。describeAsFixedLengthString() 方法是 Double 类型的自定义方法。你可以在 DoubleExtension.swift 中了解它的工作原理。' - 内容: 'This deinitializer runs when a MotionDetector instance is about to go away. It’s important to clean up here; otherwise the timer would continue to run even after the motion detector is gone.' 提示: '' - 翻译: '' + 翻译: '这个析构器会在 MotionDetector 实例即将消失时运行。在这里做一些善后工作是很重要的,否则计时器会在 motion detector 消失后继续运行。' - 内容: 'This method stops updating the motion data. It does two important things:' 提示: '' - 翻译: '' + 翻译: '这个方法会停止更新运动数据。它做了两件重要的事情:' - 内容: 'Step 17' 提示: '' 翻译: '' @@ -145,7 +145,7 @@ 翻译: '' - 内容: 'With a monospaced font, each character has the same width. (For example, the strings 1.01 and 3.14 have different widths with a proportional font like Helvetica or Times, but 1.01 and 3.14 have the same width with a monospaced font like Courier or Menlo.)' 提示: '' - 翻译: '' + 翻译: '在等宽字体下,每个字符的宽度都是相同的。(例如,1.01 和 3.14 这两个字符串在 Helvetica 或 Times 等比例字体下的宽度是不同的,但在 Courier 或 Menlo 等等宽字体下,1.01 和 3.14 的宽度是相同的。)' - 内容: 'The overlay is useful here because it positions the level’s components relative to the circle they’re drawn in.' 提示: '' 翻译: '' @@ -157,34 +157,34 @@ 翻译: '' - 内容: 'Use the attitude property to get the device’s tilt in three directions. You may be familiar with X, Y, and Z axes in 3D space. Pitch, roll, and yaw are numbers that describe rotation along those axes.' 提示: '' - 翻译: '' + 翻译: '使用 attitude 属性来获取设备在三个方向上的倾斜。你可能熟悉 3D 空间中的 X、Y 和 Z。Pitch(俯仰)、roll(翻滚)和 yaw(偏航)是描述沿这些轴旋转程度的数字。' - 内容: 'You can use the MotionDetector class to observe the motion of your device.' 提示: '' - 翻译: '' + 翻译: '你可以使用这个 MotionDetector 类来观察你的设备的运动。' - 内容: 'A CMDeviceMotion instance represents device motion, stored here in data. It has quite a few properties describing the input from the motion sensors.' 提示: '' - 翻译: '' + 翻译: 'CMDeviceMotion 实例代表设备的运动,存储在 data 中。它有很多属性来描述传感器的输入。' - 内容: 'The block of code at the end of the line that reads { _ in is the start of a closure containing the code that the timer runs. The closure calls updateMotionData().' 提示: '' - 翻译: '' + 翻译: '第一行最末端的 { _ in 是一个闭包的开始,包含了定时器运行的代码。这个闭包会调用 updateMotionData() 方法。' - 内容: 'This property calculates the vertical position of the bubble in the same way that bubbleXPosition works.' 提示: '' 翻译: '' - 内容: 'Because this view uses a published value from detector, SwiftUI updates it any time the motion detector’s roll value changes.' 提示: '' - 翻译: '' + 翻译: '因为这个视图使用了 detector 的一个 published value,所以 SwiftUI 会在运动检测器的翻滚角的值发生变化时更新它。' - 内容: 'This method starts updating the motion detector.' 提示: '' - 翻译: '' + 翻译: '这个方法会开始用传感器的数据更新我们的运动检测器的数据。' - 内容: 'You use a CMMotionManager object to get motion data from sensors, such as the accelerometer. It gathers information from the sensors and translates their data into values that you can understand.' 提示: '' - 翻译: '' + 翻译: '你将会使用 CMMotionManager 对象来获取传感器的运动数据,例如加速计。它会从传感器中收集信息,并将它们的数据转换为你可以理解的值。' - 内容: 'Step 11' 提示: '' 翻译: '' - 内容: 'A bubble level helps you determine whether something is level or tilted.' 提示: '' - 翻译: '' + 翻译: '气泡水平仪可帮助您确定一个物体是水平还是倾斜。' - 内容: 'While you can write all of the code here in a longer mathematical expression, decomposing the code makes it easier to understand. (Can you imagine having to explain this code if it were written in one line?!)' 提示: '' 翻译: '' @@ -193,16 +193,16 @@ 翻译: '' - 内容: 'These three properties store data for the tilt of your device in two dimensions (roll and pitch), as well as its vertical acceleration (zAcceleration).' 提示: '' - 翻译: '' + 翻译: '这三个属性存储了你的设备在两个维度上的倾斜数据(roll 和 pitch),以及它的垂直加速度(zAcceleration)。' - 内容: 'You can choose an update interval that makes sense for your app. For example, you’ll want a short update interval for the bubble level in this project because the interface presents real-time data as the device moves.' 提示: '' - 翻译: '' + 翻译: '你可以选择一个对你的应用程序有意义的更新间隔。例如,你将希望这个项目中的气泡水平仪有一个短的更新间隔,因为界面会随着设备的移动而实时显示数据。' - 内容: 'The .font modifier formats this Text view with a monospaced font. By default, a Text view uses a system font with proportional width, but that causes the text view to change its width as the numbers change.' 提示: '' - 翻译: '' + 翻译: '.font 装饰器使用等宽字体格式化这个 Text 视图。默认情况下,Text 视图使用系统字体,它的宽度是比例宽度,但这会导致 Text 视图在数字变化时改变它的宽度。' - 内容: 'Always use isDeviceMotionAvailable to verify that motion data is available before you try to access it.' 提示: '' - 翻译: '' + 翻译: '在你想要访问运动数据之前,记得始终使用 isDeviceMotionAvailable 来验证运动数据是否可用。' - 内容: 'The .overlay modifier adds a view on top of the circle that occupies the same area.' 提示: '' 翻译: '' @@ -214,46 +214,46 @@ 翻译: '' - 内容: 'Access and display device sensor data by subscribing to notifications.' 提示: '' - 翻译: '' + 翻译: '通过订阅通知来访问和显示设备传感器数据。' - 内容: 'Step 16' 提示: '' 翻译: '' - 内容: 'This property holds a MotionDetector instance. The motion detector senses changes in your device’s motion and provides that data for you to use in your code.' 提示: '' - 翻译: '' + 翻译: '这个属性会持有一个 MotionDetector 实例。运动检测器会感知你的设备运动的变化,并为你提供这些数据,以便你在代码中使用。' - 内容: 'First, it tells the CMMotionManager to stop updating its values by calling stopDeviceMotionUpdates(), then it stops the timer by calling invalidate().' 提示: '' - 翻译: '' + 翻译: '首先,它会通过调用 stopDeviceMotionUpdates() 来告诉 CMMotionManager 停止更新它的值,然后通过调用 invalidate() 来停止定时器。' - 内容: 'Step 2' 提示: '' 翻译: '' - 内容: 'Learn to display motion data as string values in the view.' 提示: '' - 翻译: '' + 翻译: '学习将运动数据显示为视图中的字符串值。' - 内容: 'This method does the core work of the motion detector. It’s responsible for updating all the published properties with current data from the sensors, as well as calling the code in onUpdate.' 提示: '' - 翻译: '' + 翻译: '这个方法是运动检测器的核心工作。它负责使用传感器的当前数据更新所有已发布的属性,以及调用 onUpdate' - 内容: 'You run the code in onUpdate just as you’d call any function, with a set of parentheses following its name.' 提示: '' - 翻译: '' + 翻译: '你可以像调用任何函数一样调用 onUpdate 中的代码,只需要在函数名后面加上一对括号。' - 内容: 'There are four other lines on the edge of the frame of the bubble level display. You can use the .position modifier to move them relative to their default position at the center of the overlay view.' 提示: '' 翻译: '' - 内容: 'This code creates a new timer and schedules it to run. The updateInterval property tells the timer how long to wait between updates, and repeats is set to true so that the timer runs forever until you stop it. (If you pass false to repeats, the timer only runs once.)' 提示: '' - 翻译: '' + 翻译: '这段代码创建了一个新的计时器并设定了其运作方式。updateInterval 属性会告诉计时器在每次数据更新之间需要等待多长时间,将 repeats 设置为 true 后,计时器就会一直运行,直到你停止它。(如果你传递 false 给 repeats,计时器只会运行一次。)' - 内容: 'First, adjust the roll value from the detector so that it has a minimum of 0 and goes up to the value of π, and store the adjusted value in zeroBasedRoll. This helps with the next part of the calculation, which needs values greater than 0.' 提示: '' 翻译: '' - 内容: 'This method tells the CMMotionManager to start updating motion data.' 提示: '' - 翻译: '' + 翻译: '这个方法会告诉 CMMotionManager 开始更新运动数据。' - 内容: 'This property stores code that runs when the MotionDetector updates its motion data. If you want to execute custom actions every time the motion data changes, you can put your own code into onUpdate in your instance of MotionDetector.' 提示: '' - 翻译: '' + 翻译: '这个属性存储了当 MotionDetector 更新其运动数据时需要运行的代码。如果你想在每次运动数据发生变化时执行自定义操作,你可以将自己的代码放到 MotionDetector 的 onUpdate 中。' - 内容: 'Here is the value for the roll of the device, presented as text.' 提示: '' - 翻译: '' + 翻译: '这里是设备的翻滚角的值,以文本形式呈现。' - 内容: 'Step 13' 提示: '' 翻译: '' @@ -283,7 +283,7 @@ 翻译: '' - 内容: 'These properties have a @Published property wrapper, which means that any SwiftUI view that depends on their values updates when they change. You make a view dependent on a published property by referring to it in the view’s code. The BubbleLevel, LevelView, and OrientationDataView views use these properties, which enables them to update when the MotionDetector detects a change to the roll, pitch, or zAcceleration values.' 提示: '' - 翻译: '' + 翻译: '这些属性有一个 @Published 属性包装器,这意味着任何依赖于它们值的 SwiftUI 视图会在它们改变时更新。你可以通过在视图的代码中引用它来使视图依赖于已发布的属性。BubbleLevel、LevelView 和 OrientationDataView 视图使用这些属性,这使它们能够在 MotionDetector 检测到 roll、pitch 或 zAcceleration 值的变化时更新。' - 内容: 'Present dynamic data in custom views.' 提示: '' 翻译: '' From 58693ec740a40dc3a7c93d3d38d2c41c6044a0d5 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 11:40:29 +0800 Subject: [PATCH 3/9] refactor: reformat order --- project/sample-apps/animatingshapes.yml | 181 ++++++------ project/sample-apps/bubblelevel.yml | 305 ++++++++++---------- project/sample-apps/recognizinggestures.yml | 1 - project/sample-apps/seismometer.yml | 1 - 4 files changed, 242 insertions(+), 246 deletions(-) diff --git a/project/sample-apps/animatingshapes.yml b/project/sample-apps/animatingshapes.yml index b01c712..be4f4ab 100644 --- a/project/sample-apps/animatingshapes.yml +++ b/project/sample-apps/animatingshapes.yml @@ -1,277 +1,276 @@ -# TODO -- 内容: 'For each BigDot, you can create a circle view with its offset, color, and scale.' +- 内容: 'Animating Shapes' 提示: '' 翻译: '' -- 内容: 'Try changing the number of columns, by changing the value for count in gridColumns. What happens if you change the colors in the colors array?' +- 内容: 'Learn how to use shapes and simple animations in SwiftUI.' 提示: '' 翻译: '' -- 内容: 'Learn how to use shapes and simple animations in SwiftUI.' +- 内容: 'First up, you’ll learn to use the SwiftUI Shape protocol to create and modify shape views.' 提示: '' 翻译: '' -- 内容: 'Step 6' +- 内容: 'You’ll learn the basics of animating views and how to create animations – some easy, some more complex!' 提示: '' 翻译: '' -- 内容: 'To make the heart pulse, you’ll tap the play button. When the heart pulses, it scales up and then back down, repeating the animation indefinitely. Your heartPulse state property determines the scale of the heart in this animation.' +- 内容: 'Heart Pulse' 提示: '' 翻译: '' -- 内容: 'In this walkthrough, you will learn how to create a custom heart shape as well as how to make it pulse. From there, you’ll learn how to scale the pulsing heart up or down.' +- 内容: 'Discover how to make a heart pulse in this basic animation.' 提示: '' 翻译: '' -- 内容: 'Rollin' Rainbow' +- 内容: 'Step 1' 提示: '' 翻译: '' -- 内容: 'Here’s the sequence: .easeInOut first creates an animation that eases in and eases out. Then .repeatForever(autoreverses: true) takes the .easeInOut animation and puts it in a loop that runs forever. Because autoreverses is true, the animation first runs forward, then in reverse before starting over. And finally, .speed(2) determines how quickly the animation runs. With an argument of 2, it runs at 200 percent of its default speed.' +- 内容: 'In this walkthrough, you will learn how to create a custom heart shape as well as how to make it pulse. From there, you’ll learn how to scale the pulsing heart up or down.' 提示: '' 翻译: '' -- 内容: 'Step 8' +- 内容: 'Step 2' 提示: '' 翻译: '' -- 内容: 'Spinning Animation' +- 内容: 'To create a heart shape, define a structure that adopts the Shape protocol by implementing the required path(in:) method.' 提示: '' 翻译: '' -- 内容: 'This is a much larger grid than Rollin’ Rainbow – there are a lot more circles and columns. See what happens when you change the number of dots in the grid. Do you need more circles in this animation?' +- 内容: 'Step 3' 提示: '' 翻译: '' -- 内容: 'When you tap play, the heartPulse value increases. Setting autoreverses to true allows the animation to first play forward, as the heart scales up, and then backward as it scales back down again.' +- 内容: 'path.move starts the path at the point of the heart.' 提示: '' 翻译: '' -- 内容: 'For each of these small rectangles, you’ll use a conditional modifier to animate their offsets to random positions in the view. This makes it look like they’re little shards of the larger rectangle that propel out in different directions.' +- 内容: 'Step 4' 提示: '' 翻译: '' -- 内容: 'Try changing the animationSpeed to something very low, like 20. How does the animation change?' +- 内容: 'path.addCurve creates a curved line from where your point is to a specified end point. This is what draws the curved sides of the heart shape.' 提示: '' 翻译: '' -- 内容: 'You may notice that the BigDot class and DotTracker both include a randomizePositions() function that do almost the same thing. The function in BigDot creates random positions for each SmallDot in its smallDot array, while the function in DotTracker creates random positions for each BigDot. Together, these functions create the changes in the offset, color, and scale values reflected by animations in your grid view.' +- 内容: 'Step 5' 提示: '' 翻译: '' -- 内容: 'The isExploded state property tracks whether the exploding animation is currently running. You’ll use this value to start all of the animations when you tap the button.' +- 内容: 'path.addArc adds the arcs at the top of the heart shape. By specifying the start and end angles, the path knows where to draw the arc. The arc is drawn off of specific points in the unit circle that you specify for the start and end angles.' 提示: '' 翻译: '' -- 内容: 'When you tap the play button, the circles animate and the randomizePositions() function is called. This causes the circles’ offsets to change, creating a dancing effect for the dots.' +- 内容: 'Step 6' 提示: '' 翻译: '' -- 内容: 'To create a heart shape, define a structure that adopts the Shape protocol by implementing the required path(in:) method.' +- 内容: 'To make the heart pulse, you’ll tap the play button. When the heart pulses, it scales up and then back down, repeating the animation indefinitely. Your heartPulse state property determines the scale of the heart in this animation.' 提示: '' 翻译: '' -- 内容: 'path.addCurve creates a curved line from where your point is to a specified end point. This is what draws the curved sides of the heart shape.' +- 内容: 'Step 7' 提示: '' 翻译: '' -- 内容: 'Heart Pulse' +- 内容: 'When you tap play, the heartPulse value increases. Setting autoreverses to true allows the animation to first play forward, as the heart scales up, and then backward as it scales back down again.' 提示: '' 翻译: '' -- 内容: 'Learn how to create an explosion effect.' +- 内容: 'Step 8' 提示: '' 翻译: '' -- 内容: 'The randomizePositions() function calls bigDot.randomizePositions(). This puts every SmallDot in the smallDot array defined in the BigDot class into random positions.' +- 内容: 'By changing the value of heartPulse inside of a withAnimation closure, you animate any changes to its value with the animation you pass in, resulting in the pulsing effect. 💗' 提示: '' 翻译: '' -- 内容: 'Step 12' +- 内容: 'Spinning Animation' 提示: '' 翻译: '' -- 内容: 'There you have it…a beautiful rolling rainbow!' +- 内容: 'Discover how to create a spinning effect.' 提示: '' 翻译: '' -- 内容: 'Previewing the Camera Output' +- 内容: 'Next, you’ll learn to create a spinning animation when you tap a button. Time to get dizzy!' 提示: '' 翻译: '' -- 内容: 'Dancing Dots' +- 内容: 'There is no preset animation that actually causes a shape to spin, but you can create the illusion of spinning by changing the width of the shape. To do this, you’ll use a width state property.' 提示: '' 翻译: '' -- 内容: 'path.addArc adds the arcs at the top of the heart shape. By specifying the start and end angles, the path knows where to draw the arc. The arc is drawn off of specific points in the unit circle that you specify for the start and end angles.' +- 内容: 'When you tap the button, the ellipse animates to change its width from 200 to 0. Notice that the Animation used is .easeInOut.repeatForever(autoreverses: true).speed(2). This chains together three animations to create a specific effect. Try to predict how each part of the animation affects the overall effect.' 提示: '' 翻译: '' -- 内容: 'The numCircles constant defines the number of circles in your grid. Your LazyVGrid uses gridColumns and numCircles to generate the initial grid of circles.' +- 内容: 'Here’s the sequence: .easeInOut first creates an animation that eases in and eases out. Then .repeatForever(autoreverses: true) takes the .easeInOut animation and puts it in a loop that runs forever. Because autoreverses is true, the animation first runs forward, then in reverse before starting over. And finally, .speed(2) determines how quickly the animation runs. With an argument of 2, it runs at 200 percent of its default speed.' 提示: '' 翻译: '' -- 内容: 'Now, a grid of big dots needs to populate the grid with five small dots for every big dot. Because there are so many dots, you’ll use a DotTracker class when publishing an array of BigDots. This is the published value you’ll track to create your animations. What happens to the animation if you increase or decrease the number of smallDots in the array?' +- 内容: 'This animation results in a spinning effect as the circle’s width changes first from 200 to 0, and then from 0 to 200, repeating the entire animation on a recurring loop.' 提示: '' 翻译: '' -- 内容: 'You’ll need a few state properties to keep track of how the circles change when you tap them. The gridColumns property defines the columns for the grid, and colors provides the color options for the rainbow effect.' +- 内容: 'Exploding Animation' 提示: '' 翻译: '' -- 内容: 'There is no preset animation that actually causes a shape to spin, but you can create the illusion of spinning by changing the width of the shape. To do this, you’ll use a width state property.' +- 内容: 'Learn how to create an explosion effect.' 提示: '' 翻译: '' -- 内容: 'Next, you’ll learn to create a spinning animation when you tap a button. Time to get dizzy!' +- 内容: 'To create an exploding animation, you’ll replace a rectangle with many small rectangular pieces that animate outward.' 提示: '' 翻译: '' -- 内容: 'Step 3' +- 内容: 'The isExploded state property tracks whether the exploding animation is currently running. You’ll use this value to start all of the animations when you tap the button.' 提示: '' 翻译: '' -- 内容: 'Use a drag gesture to move a grid of dots.' +- 内容: 'In the large Rectangle view, the opacity animates from 1 to 0 when isExploded is set to true; this makes the large rectangle disappear.' 提示: '' 翻译: '' -- 内容: 'This animation results in a spinning effect as the circle’s width changes first from 200 to 0, and then from 0 to 200, repeating the entire animation on a recurring loop.' +- 内容: 'When the large rectangle disappears, you want many small rectangles to explode outward. To create this effect, you’ll first generate a large number of smaller rectangles using a ForEach. These rectangles are initially hidden behind the large rectangle in a ZStack. When the large rectangle disappears, you’ll see the smaller rectangles.' 提示: '' 翻译: '' -- 内容: 'Make the circles boogie!' +- 内容: 'Experiment' 提示: '' 翻译: '' -- 内容: 'Now you know how to create more complex animations with shapes. Time to take what you’ve learned in this guide and use it to make some cool Swift apps!' +- 内容: 'Try changing the number of small rectangles to see how that affects the animation.' 提示: '' 翻译: '' -- 内容: 'Add a twist! Try changing the speed of the ease-in -out animation for the small rectangles and see what happens.' +- 内容: 'For each of these small rectangles, you’ll use a conditional modifier to animate their offsets to random positions in the view. This makes it look like they’re little shards of the larger rectangle that propel out in different directions.' 提示: '' 翻译: '' -- 内容: 'Because the index of circles starts at 0, you need to set the scaleFactor using index+1 so you never have to set the scaleFactor to an undefined number.' +- 内容: 'Add a twist! Try changing the speed of the ease-in -out animation for the small rectangles and see what happens.' 提示: '' 翻译: '' -- 内容: 'When the offset changes, you’ll animate the circles to their new positions. Instead of moving all of the dots at the same time, you can use delay on the animation so that each circle moves individually. If you set the delay based on each circle’s index, the circles will have a slightly different delay. This results in the entire grid animating one circle after the other. Because this animation would otherwise be very slow, you can divide the value for delay by the animationSpeed value to speed it up.' +- 内容: 'As those little rectangles explode out, you’ll fade their opacity from 1 to 0 so they eventually disappear. And that’s your explosion animation. Now, you may be thinking, “This isn’t a real explosion, it’s an illusion.”, and you’re absolutely right. All animations are illusions, and you’re the magician who creates them. 🪄' 提示: '' 翻译: '' -- 内容: 'Step 10' +- 内容: 'Use scaling and animation delays to create a wave effect.' 提示: '' 翻译: '' -- 内容: 'When you create a bigDot, you also need to create an array of small dots that are linked to the big dot.' +- 内容: 'Now that you’ve dabbled with some basic animations, take a look at how you can combine them to create a more advanced interactive effect. You’ll learn how to animate a grid of circles to form a fabulous wave effect when you tap them. In the preview, try tapping on different circles in the grid. What do you notice?' 提示: '' 翻译: '' -- 内容: 'Animating Shapes' +- 内容: 'You’ll need a few state properties to keep track of how the circles change when you tap them. The gridColumns property defines the columns for the grid, and colors provides the color options for the rainbow effect.' 提示: '' 翻译: '' -- 内容: 'Draggin’ Drop Dots is very similar to Rollin’ Rainbow, but with some differences. Instead of changing the scale of the circles when you tap them, the circle’s offset changes based on a drag gesture applied to the entire grid. Time to dive into the code.' +- 内容: 'Try changing the number of columns, by changing the value for count in gridColumns. What happens if you change the colors in the colors array?' 提示: '' 翻译: '' -- 内容: 'Because everything is animating, adding drawingGroup() helps to make the animation render smoothly.' +- 内容: 'The numCircles constant defines the number of circles in your grid. Your LazyVGrid uses gridColumns and numCircles to generate the initial grid of circles.' 提示: '' 翻译: '' -- 内容: 'Step 5' +- 内容: 'Try changing the value of numCircles and see how your grid changes.' 提示: '' 翻译: '' -- 内容: 'Step 7' +- 内容: 'The springAnimation constant defines the animation to use later in the animation modifier.' 提示: '' 翻译: '' -- 内容: 'The tapGesture modifier allows you to change the scaleFactor by tapping a circle in the grid. When you tap a circle, the value of scaleFactor is set based on that circle’s index. The further the circle’s position is in the grid, the larger the scaleFactor will be.' +- 内容: 'Try changing some of these values and tap the grid to see how they affect the animation.' 提示: '' 翻译: '' -- 内容: 'The springAnimation constant defines the animation to use later in the animation modifier.' +- 内容: 'Your springAnimation is used to animate changes to the scale of the circles in the grid. However, to create a rolling wave effect you want to animate the circles in your grids at different times. Add delay(_:) to springAnimation to specify the duration of the animation delay for each individual circle. To calculate the delay, divide the circle’s index by the number of columns, taking the truncating remainder as a value between 1 and 10 (the number of columns). This creates a per-column animation effect.' 提示: '' 翻译: '' - 内容: 'The .animation modifier determines how the circle animates, but the value for scaleFactor and any changes made to scaleFactor are what causes the increase in scale.' 提示: '' 翻译: '' -- 内容: 'As those little rectangles explode out, you’ll fade their opacity from 1 to 0 so they eventually disappear. And that’s your explosion animation. Now, you may be thinking, “This isn’t a real explosion, it’s an illusion.”, and you’re absolutely right. All animations are illusions, and you’re the magician who creates them. 🪄' +- 内容: 'The tapGesture modifier allows you to change the scaleFactor by tapping a circle in the grid. When you tap a circle, the value of scaleFactor is set based on that circle’s index. The further the circle’s position is in the grid, the larger the scaleFactor will be.' 提示: '' 翻译: '' -- 内容: 'path.move starts the path at the point of the heart.' +- 内容: 'Because the index of circles starts at 0, you need to set the scaleFactor using index+1 so you never have to set the scaleFactor to an undefined number.' 提示: '' 翻译: '' -- 内容: 'Discover how to create a spinning effect.' +- 内容: 'Step 9' 提示: '' 翻译: '' -- 内容: 'Because every BigDot has five SmallDots, you can do the same thing for the small dots.' +- 内容: 'There you have it…a beautiful rolling rainbow!' 提示: '' 翻译: '' -- 内容: 'Your springAnimation is used to animate changes to the scale of the circles in the grid. However, to create a rolling wave effect you want to animate the circles in your grids at different times. Add delay(_:) to springAnimation to specify the duration of the animation delay for each individual circle. To calculate the delay, divide the circle’s index by the number of columns, taking the truncating remainder as a value between 1 and 10 (the number of columns). This creates a per-column animation effect.' +- 内容: 'Try tinkering with this animation until it’s exactly as you like it. Good luck!' 提示: '' 翻译: '' -- 内容: 'Step 11' +- 内容: 'Use a drag gesture to move a grid of dots.' 提示: '' 翻译: '' -- 内容: 'Your bigDots array has 100 BigDot instances that appear in the grid view.' +- 内容: 'Draggin’ Drop Dots is very similar to Rollin’ Rainbow, but with some differences. Instead of changing the scale of the circles when you tap them, the circle’s offset changes based on a drag gesture applied to the entire grid. Time to dive into the code.' 提示: '' 翻译: '' -- 内容: 'You’ll learn the basics of animating views and how to create animations – some easy, some more complex!' +- 内容: 'This is a much larger grid than Rollin’ Rainbow – there are a lot more circles and columns. See what happens when you change the number of dots in the grid. Do you need more circles in this animation?' 提示: '' 翻译: '' -- 内容: 'First up, you’ll learn to use the SwiftUI Shape protocol to create and modify shape views.' +- 内容: 'Add a drag gesture instead of a tap gesture so the grid moves when you drag it. You can use the translation value in the drag gesture closure to set the offset of each circle, resulting in the entire grid moving to the new drag.translation value.' 提示: '' 翻译: '' -- 内容: 'Try tinkering with this animation until it’s exactly as you like it. Good luck!' +- 内容: 'When the offset changes, you’ll animate the circles to their new positions. Instead of moving all of the dots at the same time, you can use delay on the animation so that each circle moves individually. If you set the delay based on each circle’s index, the circles will have a slightly different delay. This results in the entire grid animating one circle after the other. Because this animation would otherwise be very slow, you can divide the value for delay by the animationSpeed value to speed it up.' 提示: '' 翻译: '' -- 内容: 'Now that you’ve dabbled with some basic animations, take a look at how you can combine them to create a more advanced interactive effect. You’ll learn how to animate a grid of circles to form a fabulous wave effect when you tap them. In the preview, try tapping on different circles in the grid. What do you notice?' +- 内容: 'Try changing the animationSpeed to something very low, like 20. How does the animation change?' 提示: '' 翻译: '' -- 内容: 'The DancingDotsView needs to define an instance of the DotTracker as a @StateObject so SwiftUI redraws its contents whenever any of the view’s dots change color or position.' +- 内容: 'Dancing Dots' 提示: '' 翻译: '' -- 内容: 'Add this isAnimating state property, which calls the resetPositions() method and resets the circle’s positions when you tap Reset.' +- 内容: 'Make the circles boogie!' 提示: '' 翻译: '' -- 内容: 'Try changing the number of small rectangles to see how that affects the animation.' +- 内容: 'Animate more complex model data in cool and interesting ways using observable objects.' 提示: '' 翻译: '' -- 内容: 'Step 16' +- 内容: 'What if the changes you want to animate aren’t coming from user actions? SwiftUI has a way of animating published values in observable objects. Create an observable object BigDot that publishes an offset, color, scale, and an array of small dot observable objects. You’ll use this object to model the view animations you want in your view.' 提示: '' 翻译: '' -- 内容: 'Step 2' +- 内容: 'Add a SmallDot observable object that publishes a color and an offset.' 提示: '' 翻译: '' -- 内容: 'Try changing the value of the scale in the randomizePositions() function. What happens to the animation when you lower the scale value?' +- 内容: 'When you create a bigDot, you also need to create an array of small dots that are linked to the big dot.' 提示: '' 翻译: '' -- 内容: 'Discover how to make a heart pulse in this basic animation.' +- 内容: 'Now, a grid of big dots needs to populate the grid with five small dots for every big dot. Because there are so many dots, you’ll use a DotTracker class when publishing an array of BigDots. This is the published value you’ll track to create your animations. What happens to the animation if you increase or decrease the number of smallDots in the array?' 提示: '' 翻译: '' -- 内容: 'Use scaling and animation delays to create a wave effect.' +- 内容: 'Your bigDots array has 100 BigDot instances that appear in the grid view.' 提示: '' 翻译: '' -- 内容: 'Experiment' +- 内容: 'You may notice that the BigDot class and DotTracker both include a randomizePositions() function that do almost the same thing. The function in BigDot creates random positions for each SmallDot in its smallDot array, while the function in DotTracker creates random positions for each BigDot. Together, these functions create the changes in the offset, color, and scale values reflected by animations in your grid view.' 提示: '' 翻译: '' -- 内容: 'In the large Rectangle view, the opacity animates from 1 to 0 when isExploded is set to true; this makes the large rectangle disappear.' +- 内容: 'Try changing the value of the scale in the randomizePositions() function. What happens to the animation when you lower the scale value?' 提示: '' 翻译: '' -- 内容: 'Animate more complex model data in cool and interesting ways using observable objects.' +- 内容: 'Add a resetPositions() function, so the dots reset to their original positions when you tap the reset button. This is very similar to the randomizePositions() function used to place circles in random locations around the view.' 提示: '' 翻译: '' -- 内容: 'Add in this ForEach loop to place each BigDot tracked by the tracker into the grid.' +- 内容: 'The randomizePositions() function calls bigDot.randomizePositions(). This puts every SmallDot in the smallDot array defined in the BigDot class into random positions.' 提示: '' 翻译: '' -- 内容: 'Step 13' +- 内容: 'The DancingDotsView needs to define an instance of the DotTracker as a @StateObject so SwiftUI redraws its contents whenever any of the view’s dots change color or position.' 提示: '' 翻译: '' -- 内容: 'Step 4' +- 内容: 'Step 10' 提示: '' 翻译: '' -- 内容: 'When the large rectangle disappears, you want many small rectangles to explode outward. To create this effect, you’ll first generate a large number of smaller rectangles using a ForEach. These rectangles are initially hidden behind the large rectangle in a ZStack. When the large rectangle disappears, you’ll see the smaller rectangles.' +- 内容: 'Add in this ForEach loop to place each BigDot tracked by the tracker into the grid.' 提示: '' 翻译: '' -- 内容: 'To create an exploding animation, you’ll replace a rectangle with many small rectangular pieces that animate outward.' +- 内容: 'Step 11' 提示: '' 翻译: '' -- 内容: 'When you tap the button, the ellipse animates to change its width from 200 to 0. Notice that the Animation used is .easeInOut.repeatForever(autoreverses: true).speed(2). This chains together three animations to create a specific effect. Try to predict how each part of the animation affects the overall effect.' +- 内容: 'For each BigDot, you can create a circle view with its offset, color, and scale.' 提示: '' 翻译: '' -- 内容: 'Try changing the value of numCircles and see how your grid changes.' +- 内容: 'Step 12' 提示: '' 翻译: '' -- 内容: 'Step 9' +- 内容: 'Because every BigDot has five SmallDots, you can do the same thing for the small dots.' 提示: '' 翻译: '' -- 内容: 'Draggin' Drop It' +- 内容: 'Step 13' 提示: '' 翻译: '' -- 内容: 'Step 14' +- 内容: 'When you tap the play button, the circles animate and the randomizePositions() function is called. This causes the circles’ offsets to change, creating a dancing effect for the dots.' 提示: '' 翻译: '' -- 内容: 'Step 1' +- 内容: 'Step 14' 提示: '' 翻译: '' -- 内容: 'Step 15' +- 内容: 'Add this isAnimating state property, which calls the resetPositions() method and resets the circle’s positions when you tap Reset.' 提示: '' 翻译: '' -- 内容: 'Add a drag gesture instead of a tap gesture so the grid moves when you drag it. You can use the translation value in the drag gesture closure to set the offset of each circle, resulting in the entire grid moving to the new drag.translation value.' +- 内容: 'Step 15' 提示: '' 翻译: '' -- 内容: 'Add a resetPositions() function, so the dots reset to their original positions when you tap the reset button. This is very similar to the randomizePositions() function used to place circles in random locations around the view.' +- 内容: 'Because everything is animating, adding drawingGroup() helps to make the animation render smoothly.' 提示: '' 翻译: '' -- 内容: 'Try changing some of these values and tap the grid to see how they affect the animation.' +- 内容: 'Step 16' 提示: '' 翻译: '' -- 内容: 'Add a SmallDot observable object that publishes a color and an offset.' +- 内容: 'Now you know how to create more complex animations with shapes. Time to take what you’ve learned in this guide and use it to make some cool Swift apps!' 提示: '' 翻译: '' -- 内容: 'Exploding Animation' +- 内容: 'Previewing the Camera Output' 提示: '' 翻译: '' - 内容: 'Preview the output from the camera.' 提示: '' 翻译: '' -- 内容: 'What if the changes you want to animate aren’t coming from user actions? SwiftUI has a way of animating published values in observable objects. Create an observable object BigDot that publishes an offset, color, scale, and an array of small dot observable objects. You’ll use this object to model the view animations you want in your view.' +- 内容: 'Rollin Rainbow' 提示: '' 翻译: '' -- 内容: 'By changing the value of heartPulse inside of a withAnimation closure, you animate any changes to its value with the animation you pass in, resulting in the pulsing effect. 💗' +- 内容: 'Draggin Drop It' 提示: '' 翻译: '' diff --git a/project/sample-apps/bubblelevel.yml b/project/sample-apps/bubblelevel.yml index 1a463e1..fd6b19c 100644 --- a/project/sample-apps/bubblelevel.yml +++ b/project/sample-apps/bubblelevel.yml @@ -1,295 +1,294 @@ -# TODO -- 内容: 'This method returns a string describing the value of a Double using a fixed number of digits. You can pass in the number of integer digits and fraction digits you want, or leave those arguments out for the default values of 2.' +- 内容: 'Bubble Level' 提示: '' 翻译: '' -- 内容: 'An extension is a way to make custom behavior for existing types. Declaring extension Double means you’re adding new capabilities to the Double type. Any time you use a Double value in your code, you can access anything defined in this extension.' +- 内容: 'Access and display device sensor data by subscribing to notifications.' 提示: '' - 翻译: '' -- 内容: 'This is the size of the level display, both width and height. You can change this value to make the display larger or smaller.' + 翻译: '通过订阅通知来访问和显示设备传感器数据。' +- 内容: 'Welcome to Bubble Level.' 提示: '' - 翻译: '' -- 内容: 'The .number style has modifiers much like those for SwiftUI views.' + 翻译: '欢迎来到“气泡水平仪”这堂课。' +- 内容: 'A bubble level helps you determine whether something is level or tilted.' 提示: '' - 翻译: '' -- 内容: 'Because detector is an observable object, any changes to its published values allows SwiftUI to automatically update any views using those values. In this case, you’ll update the bubble’s position.' + 翻译: '气泡水平仪可帮助您确定一个物体是水平还是倾斜。' +- 内容: 'This app displays the orientation of your device as numbers and as a graphical version of a bubble level. Try tilting your device and watch the bubble move. Try to make your device level by centering the bubble in the crosshairs. Or place it on a surface like your bedroom floor to determine whether the floor is level.' 提示: '' - 翻译: '因为 detector 是一个可观察对象,所以任何对它的 published 值的更改都会使 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,你将更新气泡的位置。' -- 内容: 'Bubble Level' + 翻译: '这个 App 将会分别以数字和可视化的气泡水平仪来显示你设备的方向。你可以尝试倾斜你的设备并观察气泡移动,通过将气泡置于十字准线中心来使设备保持水平。或者将其放在卧室地板等表面上,以确定地板是否水平。' +- 内容: 'Motion Detector' 提示: '' 翻译: '' -- 内容: 'This property represents the range of values the motion detector reports as you tilt the device (assuming you don’t turn it upside down). Negative values indicate a tilt to the left, and positive values indicate a tilt to the right. (You could assign the value 3.14 to this property, but Double.pi is convenient shorthand for the mathematical constant π, and it’s a closer approximation because it includes many digits of precision.)' +- 内容: 'You can use the MotionDetector class to observe the motion of your device.' 提示: '' - 翻译: '' -- 内容: 'This property holds a MotionDetector instance, which senses changes in your device’s motion. You can access this instance in your code to update the user interface as the motion data changes.' + 翻译: '你可以使用这个 MotionDetector 类来观察你的设备的运动。' +- 内容: 'Step 1' 提示: '' 翻译: '' -- 内容: 'Step 6' +- 内容: 'Your device has sensors such as accelerometers and gyroscopes that it uses to sense motion and orientation. The Core Motion framework gives you access to data from these and other sensors.' + 提示: '' + 翻译: '你的设备有加速计和陀螺仪等传感器,它们用于感知运动和方向。Core Motion 框架可以让你访问这些传感器和其他传感器的数据。' +- 内容: 'Step 2' 提示: '' 翻译: '' -- 内容: 'Bubble Level View' +- 内容: 'You use a CMMotionManager object to get motion data from sensors, such as the accelerometer. It gathers information from the sensors and translates their data into values that you can understand.' + 提示: '' + 翻译: '你将会使用 CMMotionManager 对象来获取传感器的运动数据,例如加速计。它会从传感器中收集信息,并将它们的数据转换为你可以理解的值。' +- 内容: 'Step 3' 提示: '' 翻译: '' -- 内容: 'Orientation Data View' +- 内容: 'The timer property stores a Timer instance. A timer waits for a period of time that you specify before running some code. The MotionDetector uses the timer to update its pitch, roll, and zAcceleration values at regular intervals, defined by the updateInterval property.' 提示: '' - 翻译: '朝向数据视图' -- 内容: 'Then, use this adjusted value to calculate the roll as a fraction of the entire range of roll values, so that full tilt left is 0.0, flat is 0.5, and full tilt right is 1.0.' + 翻译: 'timer 这个属性存储了一个 Timer 实例。Timer 会在你指定的时间段之后运行一些代码。MotionDetector 使用 timer 来在 updateInterval 属性定义的时间间隔内更新它的 pitch、roll 和 zAcceleration 值。' +- 内容: 'Step 4' 提示: '' 翻译: '' -- 内容: 'Step 8' +- 内容: 'You can choose an update interval that makes sense for your app. For example, you’ll want a short update interval for the bubble level in this project because the interface presents real-time data as the device moves.' + 提示: '' + 翻译: '你可以选择一个对你的应用程序有意义的更新间隔。例如,你将希望这个项目中的气泡水平仪有一个短的更新间隔,因为界面会随着设备的移动而实时显示数据。' +- 内容: 'Step 5' 提示: '' 翻译: '' -- 内容: 'The .sign modifier lets you format the number so that it’s always preceded by a sign, even when the number is positive.' +- 内容: 'These three properties store data for the tilt of your device in two dimensions (roll and pitch), as well as its vertical acceleration (zAcceleration).' + 提示: '' + 翻译: '这三个属性存储了你的设备在两个维度上的倾斜数据(roll 和 pitch),以及它的垂直加速度(zAcceleration)。' +- 内容: 'Step 6' 提示: '' 翻译: '' -- 内容: 'The deviceMotion data may not be there in certain conditions. The way you can tell if the data exists is to try to assign it to a variable or constant using if let. If the motion data exists, it’s assigned to data and the code inside the braces runs. Otherwise, it skips the entire if statement.' +- 内容: 'These properties have a @Published property wrapper, which means that any SwiftUI view that depends on their values updates when they change. You make a view dependent on a published property by referring to it in the view’s code. The BubbleLevel, LevelView, and OrientationDataView views use these properties, which enables them to update when the MotionDetector detects a change to the roll, pitch, or zAcceleration values.' 提示: '' - 翻译: '在一些情况下,deviceMotion 数据可能不存在。你可以通过 if let 来判断数据是否存在。如果 motion 数据存在,它会被赋值给 data 并且大括号内的代码会被执行。否则,整个 if 语句会被跳过。' -- 内容: 'Investigate using an extension on Double to format them in an easy to read way.' + 翻译: '这些属性有一个 @Published 属性包装器,这意味着任何依赖于它们值的 SwiftUI 视图会在它们改变时更新。你可以通过在视图的代码中引用它来使视图依赖于已发布的属性。BubbleLevel、LevelView 和 OrientationDataView 视图使用这些属性,这使它们能够在 MotionDetector 检测到 roll、pitch 或 zAcceleration 值的变化时更新。' +- 内容: 'Step 7' 提示: '' 翻译: '' -- 内容: 'The timer property stores a Timer instance. A timer waits for a period of time that you specify before running some code. The MotionDetector uses the timer to update its pitch, roll, and zAcceleration values at regular intervals, defined by the updateInterval property.' +- 内容: 'This property stores code that runs when the MotionDetector updates its motion data. If you want to execute custom actions every time the motion data changes, you can put your own code into onUpdate in your instance of MotionDetector.' 提示: '' - 翻译: 'timer 这个属性存储了一个 Timer 实例。Timer 会在你指定的时间段之后运行一些代码。MotionDetector 使用 timer 来在 updateInterval 属性定义的时间间隔内更新它的 pitch、roll 和 zAcceleration 值。' -- 内容: 'Seismometer' + 翻译: '这个属性存储了当 MotionDetector 更新其运动数据时需要运行的代码。如果你想在每次运动数据发生变化时执行自定义操作,你可以将自己的代码放到 MotionDetector 的 onUpdate 中。' +- 内容: 'Step 8' 提示: '' 翻译: '' -- 内容: 'The .number style gives you a string describing this Double value as a simple number, as opposed to a percentage or a price.' +- 内容: 'This method starts updating the motion detector.' + 提示: '' + 翻译: '这个方法会开始用传感器的数据更新我们的运动检测器的数据。' +- 内容: 'Step 9' 提示: '' 翻译: '' -- 内容: 'The OrientationDataView displays the roll and pitch of your iPad as numbers. Roll is the degree of left and right tilt, and pitch is the degree of forward and backward tilt.' +- 内容: 'Always use isDeviceMotionAvailable to verify that motion data is available before you try to access it.' 提示: '' - 翻译: 'OrientationDataView 会将你的 iPad 的翻滚角和俯仰角以数字的形式显示出来。翻滚角是左右倾斜的角度,俯仰角是前后倾斜的角度。' -- 内容: 'This app displays the orientation of your device as numbers and as a graphical version of a bubble level. Try tilting your device and watch the bubble move. Try to make your device level by centering the bubble in the crosshairs. Or place it on a surface like your bedroom floor to determine whether the floor is level.' + 翻译: '在你想要访问运动数据之前,记得始终使用 isDeviceMotionAvailable 来验证运动数据是否可用。' +- 内容: 'Step 10' 提示: '' - 翻译: '这个 App 将会分别以数字和可视化的气泡水平仪来显示你设备的方向。你可以尝试倾斜你的设备并观察气泡移动,通过将气泡置于十字准线中心来使设备保持水平。或者将其放在卧室地板等表面上,以确定地板是否水平。' -- 内容: 'This property calculates the horizontal placement of the bubble using three steps.' + 翻译: '' +- 内容: 'This method tells the CMMotionManager to start updating motion data.' + 提示: '' + 翻译: '这个方法会告诉 CMMotionManager 开始更新运动数据。' +- 内容: 'Step 11' 提示: '' 翻译: '' +- 内容: 'This code creates a new timer and schedules it to run. The updateInterval property tells the timer how long to wait between updates, and repeats is set to true so that the timer runs forever until you stop it. (If you pass false to repeats, the timer only runs once.)' + 提示: '' + 翻译: '这段代码创建了一个新的计时器并设定了其运作方式。updateInterval 属性会告诉计时器在每次数据更新之间需要等待多长时间,将 repeats 设置为 true 后,计时器就会一直运行,直到你停止它。(如果你传递 false 给 repeats,计时器只会运行一次。)' - 内容: 'Step 12' 提示: '' 翻译: '' -- 内容: 'A ZStack view allows you to draw the components of the level over each other.' +- 内容: 'The block of code at the end of the line that reads { _ in is the start of a closure containing the code that the timer runs. The closure calls updateMotionData().' + 提示: '' + 翻译: '第一行最末端的 { _ in 是一个闭包的开始,包含了定时器运行的代码。这个闭包会调用 updateMotionData() 方法。' +- 内容: 'Step 13' 提示: '' 翻译: '' -- 内容: 'Welcome to Bubble Level.' +- 内容: 'This method does the core work of the motion detector. It’s responsible for updating all the published properties with current data from the sensors, as well as calling the code in onUpdate.' 提示: '' - 翻译: '欢迎来到“气泡水平仪”这堂课。' -- 内容: 'Multiplying the fraction with the size of the level gives you the X position of the bubble.' + 翻译: '这个方法是运动检测器的核心工作。它负责使用传感器的当前数据更新所有已发布的属性,以及调用 onUpdate' +- 内容: 'Step 14' 提示: '' 翻译: '' -- 内容: 'Because detector is an observable object, any changes made to its published values cause SwiftUI to automatically update any views using those values. In this case, changes from the device’s sensors update the Text view with the latest values for the pitch and roll.' +- 内容: 'The deviceMotion data may not be there in certain conditions. The way you can tell if the data exists is to try to assign it to a variable or constant using if let. If the motion data exists, it’s assigned to data and the code inside the braces runs. Otherwise, it skips the entire if statement.' 提示: '' - 翻译: '因为 detector 是一个可观察对象,所以对它的 published 值所做的任何更改都会导致 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,来自设备传感器的更改会使用最新的俯仰角和翻滚角的值更新 Text 视图上的字符。' -- 内容: 'Step 20' + 翻译: '在一些情况下,deviceMotion 数据可能不存在。你可以通过 if let 来判断数据是否存在。如果 motion 数据存在,它会被赋值给 data 并且大括号内的代码会被执行。否则,整个 if 语句会被跳过。' +- 内容: 'Step 15' 提示: '' 翻译: '' -- 内容: 'Step 23' +- 内容: 'A CMDeviceMotion instance represents device motion, stored here in data. It has quite a few properties describing the input from the motion sensors.' + 提示: '' + 翻译: 'CMDeviceMotion 实例代表设备的运动,存储在 data 中。它有很多属性来描述传感器的输入。' +- 内容: 'Step 16' 提示: '' 翻译: '' -- 内容: 'Step 3' +- 内容: 'Use the attitude property to get the device’s tilt in three directions. You may be familiar with X, Y, and Z axes in 3D space. Pitch, roll, and yaw are numbers that describe rotation along those axes.' + 提示: '' + 翻译: '使用 attitude 属性来获取设备在三个方向上的倾斜。你可能熟悉 3D 空间中的 X、Y 和 Z。Pitch(俯仰)、roll(翻滚)和 yaw(偏航)是描述沿这些轴旋转程度的数字。' +- 内容: 'Step 17' 提示: '' 翻译: '' - 内容: 'Use the userAcceleration property to get the device’s acceleration after accounting for the downward pull of gravity. If it’s at rest, this number is 0. If it’s accelerating upward, the number is negative, and if it’s accelerating downward, the number is positive.' 提示: '' 翻译: '使用 userAcceleration 属性来获取设备在考虑到重力向下拉的情况下的加速度。如果它处于静止状态,这个数值为 0。如果它向上加速,这个数值为负数,如果它向下加速,这个数值为正数。' -- 内容: 'Because all of these calculations are hidden in a property, your view’s body code remains simple and readable.' +- 内容: 'Step 18' 提示: '' 翻译: '' -- 内容: 'Your device has sensors such as accelerometers and gyroscopes that it uses to sense motion and orientation. The Core Motion framework gives you access to data from these and other sensors.' - 提示: '' - 翻译: '你的设备有加速计和陀螺仪等传感器,它们用于感知运动和方向。Core Motion 框架可以让你访问这些传感器和其他传感器的数据。' -- 内容: 'These two computed properties provide the strings used in the view. They take the roll or pitch value from the motion detector and format that number as a string with a fixed number of digits. The describeAsFixedLengthString() method is a custom method on the Double type. You can learn how it works in DoubleExtension.swift.' +- 内容: 'You run the code in onUpdate just as you’d call any function, with a set of parentheses following its name.' 提示: '' - 翻译: '这两个计算属性提供了视图中使用的字符串。它们从 motion detector 中获取翻滚角或俯仰角的值,并将该数字格式化为具有固定位数的字符串。describeAsFixedLengthString() 方法是 Double 类型的自定义方法。你可以在 DoubleExtension.swift 中了解它的工作原理。' -- 内容: 'This deinitializer runs when a MotionDetector instance is about to go away. It’s important to clean up here; otherwise the timer would continue to run even after the motion detector is gone.' + 翻译: '你可以像调用任何函数一样调用 onUpdate 中的代码,只需要在函数名后面加上一对括号。' +- 内容: 'Step 19' 提示: '' - 翻译: '这个析构器会在 MotionDetector 实例即将消失时运行。在这里做一些善后工作是很重要的,否则计时器会在 motion detector 消失后继续运行。' + 翻译: '' - 内容: 'This method stops updating the motion data. It does two important things:' 提示: '' 翻译: '这个方法会停止更新运动数据。它做了两件重要的事情:' -- 内容: 'Step 17' +- 内容: 'Step 20' 提示: '' 翻译: '' -- 内容: 'Step 10' +- 内容: 'First, it tells the CMMotionManager to stop updating its values by calling stopDeviceMotionUpdates(), then it stops the timer by calling invalidate().' 提示: '' - 翻译: '' -- 内容: 'This property returns a vertical line that you use to draw the bubble level display. Because there are multiple identical vertical lines, you can use this property whenever you need one rather than repeating the more complex code inside it.' + 翻译: '首先,它会通过调用 stopDeviceMotionUpdates() 来告诉 CMMotionManager 停止更新它的值,然后通过调用 invalidate() 来停止定时器。' +- 内容: 'Step 21' 提示: '' 翻译: '' -- 内容: 'In the center are a smaller circle and a crosshair made of two lines: one horizontal and one vertical.' +- 内容: 'This deinitializer runs when a MotionDetector instance is about to go away. It’s important to clean up here; otherwise the timer would continue to run even after the motion detector is gone.' 提示: '' - 翻译: '' -- 内容: 'Double Extension' + 翻译: '这个析构器会在 MotionDetector 实例即将消失时运行。在这里做一些善后工作是很重要的,否则计时器会在 motion detector 消失后继续运行。' +- 内容: 'Orientation Data View' 提示: '' - 翻译: '' -- 内容: 'Learn to display the tilt of your device using a bubble level UI.' + 翻译: '朝向数据视图' +- 内容: 'Learn to display motion data as string values in the view.' 提示: '' - 翻译: '' -- 内容: 'The .precision modifier lets you specify exactly how many digits to use.' + 翻译: '学习将运动数据显示为视图中的字符串值。' +- 内容: 'The OrientationDataView displays the roll and pitch of your iPad as numbers. Roll is the degree of left and right tilt, and pitch is the degree of forward and backward tilt.' 提示: '' - 翻译: '' -- 内容: 'The argument to formatted() is a format style.' + 翻译: 'OrientationDataView 会将你的 iPad 的翻滚角和俯仰角以数字的形式显示出来。翻滚角是左右倾斜的角度,俯仰角是前后倾斜的角度。' +- 内容: 'This property holds a MotionDetector instance. The motion detector senses changes in your device’s motion and provides that data for you to use in your code.' 提示: '' - 翻译: '' -- 内容: 'Because these properties use published values from MotionDetector, SwiftUI updates the bubble view’s position each time they change.' + 翻译: '这个属性会持有一个 MotionDetector 实例。运动检测器会感知你的设备运动的变化,并为你提供这些数据,以便你在代码中使用。' +- 内容: 'Because detector is an observable object, any changes made to its published values cause SwiftUI to automatically update any views using those values. In this case, changes from the device’s sensors update the Text view with the latest values for the pitch and roll.' 提示: '' - 翻译: '' -- 内容: 'Step 7' + 翻译: '因为 detector 是一个可观察对象,所以对它的 published 值所做的任何更改都会导致 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,来自设备传感器的更改会使用最新的俯仰角和翻滚角的值更新 Text 视图上的字符。' +- 内容: 'These two computed properties provide the strings used in the view. They take the roll or pitch value from the motion detector and format that number as a string with a fixed number of digits. The describeAsFixedLengthString() method is a custom method on the Double type. You can learn how it works in DoubleExtension.swift.' 提示: '' - 翻译: '' -- 内容: 'Step 5' + 翻译: '这两个计算属性提供了视图中使用的字符串。它们从 motion detector 中获取翻滚角或俯仰角的值,并将该数字格式化为具有固定位数的字符串。describeAsFixedLengthString() 方法是 Double 类型的自定义方法。你可以在 DoubleExtension.swift 中了解它的工作原理。' +- 内容: 'Here is the value for the roll of the device, presented as text.' 提示: '' - 翻译: '' -- 内容: 'It’s useful to define and use constants like these for important values in your code, rather than using the values themselves. When you read the code, you’ll have a better idea of what it does than if you see a lot of numbers with no context.' + 翻译: '这里是设备的翻滚角的值,以文本形式呈现。' +- 内容: 'Because this view uses a published value from detector, SwiftUI updates it any time the motion detector’s roll value changes.' 提示: '' - 翻译: '' + 翻译: '因为这个视图使用了 detector 的一个 published value,所以 SwiftUI 会在运动检测器的翻滚角的值发生变化时更新它。' +- 内容: 'The .font modifier formats this Text view with a monospaced font. By default, a Text view uses a system font with proportional width, but that causes the text view to change its width as the numbers change.' + 提示: '' + 翻译: '.font 装饰器使用等宽字体格式化这个 Text 视图。默认情况下,Text 视图使用系统字体,它的宽度是比例宽度,但这会导致 Text 视图在数字变化时改变它的宽度。' - 内容: 'With a monospaced font, each character has the same width. (For example, the strings 1.01 and 3.14 have different widths with a proportional font like Helvetica or Times, but 1.01 and 3.14 have the same width with a monospaced font like Courier or Menlo.)' 提示: '' 翻译: '在等宽字体下,每个字符的宽度都是相同的。(例如,1.01 和 3.14 这两个字符串在 Helvetica 或 Times 等比例字体下的宽度是不同的,但在 Courier 或 Menlo 等等宽字体下,1.01 和 3.14 的宽度是相同的。)' -- 内容: 'The overlay is useful here because it positions the level’s components relative to the circle they’re drawn in.' +- 内容: 'Bubble Level View' 提示: '' 翻译: '' -- 内容: 'Step 18' +- 内容: 'Learn to display the tilt of your device using a bubble level UI.' 提示: '' - 翻译: '' -- 内容: 'Step 22' + 翻译: '学习如何使用气泡水平仪的 UI 来显示设备的倾斜。' +- 内容: 'This view displays the tilt of your device by drawing a circle within a larger circular boundary with crosshairs to indicate its centerpoint. When your device is level, the bubble rests at the center of the frame. Try tilting your device to see how the bubble moves.' 提示: '' 翻译: '' -- 内容: 'Use the attitude property to get the device’s tilt in three directions. You may be familiar with X, Y, and Z axes in 3D space. Pitch, roll, and yaw are numbers that describe rotation along those axes.' +- 内容: 'This property holds a MotionDetector instance, which senses changes in your device’s motion. You can access this instance in your code to update the user interface as the motion data changes.' 提示: '' - 翻译: '使用 attitude 属性来获取设备在三个方向上的倾斜。你可能熟悉 3D 空间中的 X、Y 和 Z。Pitch(俯仰)、roll(翻滚)和 yaw(偏航)是描述沿这些轴旋转程度的数字。' -- 内容: 'You can use the MotionDetector class to observe the motion of your device.' + 翻译: '' +- 内容: 'Because detector is an observable object, any changes to its published values allows SwiftUI to automatically update any views using those values. In this case, you’ll update the bubble’s position.' 提示: '' - 翻译: '你可以使用这个 MotionDetector 类来观察你的设备的运动。' -- 内容: 'A CMDeviceMotion instance represents device motion, stored here in data. It has quite a few properties describing the input from the motion sensors.' + 翻译: '因为 detector 是一个可观察对象,所以任何对它的 published 值的更改都会使 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,你将更新气泡的位置。' +- 内容: 'This property represents the range of values the motion detector reports as you tilt the device (assuming you don’t turn it upside down). Negative values indicate a tilt to the left, and positive values indicate a tilt to the right. (You could assign the value 3.14 to this property, but Double.pi is convenient shorthand for the mathematical constant π, and it’s a closer approximation because it includes many digits of precision.)' 提示: '' - 翻译: 'CMDeviceMotion 实例代表设备的运动,存储在 data 中。它有很多属性来描述传感器的输入。' -- 内容: 'The block of code at the end of the line that reads { _ in is the start of a closure containing the code that the timer runs. The closure calls updateMotionData().' + 翻译: '' +- 内容: 'This is the size of the level display, both width and height. You can change this value to make the display larger or smaller.' 提示: '' - 翻译: '第一行最末端的 { _ in 是一个闭包的开始,包含了定时器运行的代码。这个闭包会调用 updateMotionData() 方法。' -- 内容: 'This property calculates the vertical position of the bubble in the same way that bubbleXPosition works.' + 翻译: '' +- 内容: 'It’s useful to define and use constants like these for important values in your code, rather than using the values themselves. When you read the code, you’ll have a better idea of what it does than if you see a lot of numbers with no context.' 提示: '' 翻译: '' -- 内容: 'Because this view uses a published value from detector, SwiftUI updates it any time the motion detector’s roll value changes.' +- 内容: 'This property calculates the horizontal placement of the bubble using three steps.' 提示: '' - 翻译: '因为这个视图使用了 detector 的一个 published value,所以 SwiftUI 会在运动检测器的翻滚角的值发生变化时更新它。' -- 内容: 'This method starts updating the motion detector.' + 翻译: '' +- 内容: 'First, adjust the roll value from the detector so that it has a minimum of 0 and goes up to the value of π, and store the adjusted value in zeroBasedRoll. This helps with the next part of the calculation, which needs values greater than 0.' 提示: '' - 翻译: '这个方法会开始用传感器的数据更新我们的运动检测器的数据。' -- 内容: 'You use a CMMotionManager object to get motion data from sensors, such as the accelerometer. It gathers information from the sensors and translates their data into values that you can understand.' + 翻译: '' +- 内容: 'Then, use this adjusted value to calculate the roll as a fraction of the entire range of roll values, so that full tilt left is 0.0, flat is 0.5, and full tilt right is 1.0.' 提示: '' - 翻译: '你将会使用 CMMotionManager 对象来获取传感器的运动数据,例如加速计。它会从传感器中收集信息,并将它们的数据转换为你可以理解的值。' -- 内容: 'Step 11' + 翻译: '' +- 内容: 'Multiplying the fraction with the size of the level gives you the X position of the bubble.' 提示: '' 翻译: '' -- 内容: 'A bubble level helps you determine whether something is level or tilted.' +- 内容: 'Because all of these calculations are hidden in a property, your view’s body code remains simple and readable.' 提示: '' - 翻译: '气泡水平仪可帮助您确定一个物体是水平还是倾斜。' + 翻译: '' - 内容: 'While you can write all of the code here in a longer mathematical expression, decomposing the code makes it easier to understand. (Can you imagine having to explain this code if it were written in one line?!)' 提示: '' 翻译: '' -- 内容: 'Motion Detector' +- 内容: 'This property calculates the vertical position of the bubble in the same way that bubbleXPosition works.' 提示: '' 翻译: '' -- 内容: 'These three properties store data for the tilt of your device in two dimensions (roll and pitch), as well as its vertical acceleration (zAcceleration).' - 提示: '' - 翻译: '这三个属性存储了你的设备在两个维度上的倾斜数据(roll 和 pitch),以及它的垂直加速度(zAcceleration)。' -- 内容: 'You can choose an update interval that makes sense for your app. For example, you’ll want a short update interval for the bubble level in this project because the interface presents real-time data as the device moves.' +- 内容: 'This property returns a vertical line that you use to draw the bubble level display. Because there are multiple identical vertical lines, you can use this property whenever you need one rather than repeating the more complex code inside it.' 提示: '' - 翻译: '你可以选择一个对你的应用程序有意义的更新间隔。例如,你将希望这个项目中的气泡水平仪有一个短的更新间隔,因为界面会随着设备的移动而实时显示数据。' -- 内容: 'The .font modifier formats this Text view with a monospaced font. By default, a Text view uses a system font with proportional width, but that causes the text view to change its width as the numbers change.' + 翻译: '' +- 内容: 'Here’s a circle with a gray foreground color that provides a visual boundary for the display.' 提示: '' - 翻译: '.font 装饰器使用等宽字体格式化这个 Text 视图。默认情况下,Text 视图使用系统字体,它的宽度是比例宽度,但这会导致 Text 视图在数字变化时改变它的宽度。' -- 内容: 'Always use isDeviceMotionAvailable to verify that motion data is available before you try to access it.' + 翻译: '' +- 内容: 'You can use a .frame modifier to give the circle a fixed width and height, which is important to draw the other components correctly.' 提示: '' - 翻译: '在你想要访问运动数据之前,记得始终使用 isDeviceMotionAvailable 来验证运动数据是否可用。' + 翻译: '' - 内容: 'The .overlay modifier adds a view on top of the circle that occupies the same area.' 提示: '' 翻译: '' -- 内容: 'Step 19' +- 内容: 'The overlay is useful here because it positions the level’s components relative to the circle they’re drawn in.' 提示: '' 翻译: '' -- 内容: 'The first circle represents the bubble. Notice that the bubbleXPosition and bubbleYPosition values position the bubble inside the overlay view.' +- 内容: 'A ZStack view allows you to draw the components of the level over each other.' 提示: '' 翻译: '' -- 内容: 'Access and display device sensor data by subscribing to notifications.' - 提示: '' - 翻译: '通过订阅通知来访问和显示设备传感器数据。' -- 内容: 'Step 16' +- 内容: 'The first circle represents the bubble. Notice that the bubbleXPosition and bubbleYPosition values position the bubble inside the overlay view.' 提示: '' 翻译: '' -- 内容: 'This property holds a MotionDetector instance. The motion detector senses changes in your device’s motion and provides that data for you to use in your code.' - 提示: '' - 翻译: '这个属性会持有一个 MotionDetector 实例。运动检测器会感知你的设备运动的变化,并为你提供这些数据,以便你在代码中使用。' -- 内容: 'First, it tells the CMMotionManager to stop updating its values by calling stopDeviceMotionUpdates(), then it stops the timer by calling invalidate().' - 提示: '' - 翻译: '首先,它会通过调用 stopDeviceMotionUpdates() 来告诉 CMMotionManager 停止更新它的值,然后通过调用 invalidate() 来停止定时器。' -- 内容: 'Step 2' +- 内容: 'Because these properties use published values from MotionDetector, SwiftUI updates the bubble view’s position each time they change.' 提示: '' 翻译: '' -- 内容: 'Learn to display motion data as string values in the view.' - 提示: '' - 翻译: '学习将运动数据显示为视图中的字符串值。' -- 内容: 'This method does the core work of the motion detector. It’s responsible for updating all the published properties with current data from the sensors, as well as calling the code in onUpdate.' - 提示: '' - 翻译: '这个方法是运动检测器的核心工作。它负责使用传感器的当前数据更新所有已发布的属性,以及调用 onUpdate' -- 内容: 'You run the code in onUpdate just as you’d call any function, with a set of parentheses following its name.' - 提示: '' - 翻译: '你可以像调用任何函数一样调用 onUpdate 中的代码,只需要在函数名后面加上一对括号。' -- 内容: 'There are four other lines on the edge of the frame of the bubble level display. You can use the .position modifier to move them relative to their default position at the center of the overlay view.' +- 内容: 'Step 22' 提示: '' 翻译: '' -- 内容: 'This code creates a new timer and schedules it to run. The updateInterval property tells the timer how long to wait between updates, and repeats is set to true so that the timer runs forever until you stop it. (If you pass false to repeats, the timer only runs once.)' - 提示: '' - 翻译: '这段代码创建了一个新的计时器并设定了其运作方式。updateInterval 属性会告诉计时器在每次数据更新之间需要等待多长时间,将 repeats 设置为 true 后,计时器就会一直运行,直到你停止它。(如果你传递 false 给 repeats,计时器只会运行一次。)' -- 内容: 'First, adjust the roll value from the detector so that it has a minimum of 0 and goes up to the value of π, and store the adjusted value in zeroBasedRoll. This helps with the next part of the calculation, which needs values greater than 0.' +- 内容: 'In the center are a smaller circle and a crosshair made of two lines: one horizontal and one vertical.' 提示: '' 翻译: '' -- 内容: 'This method tells the CMMotionManager to start updating motion data.' - 提示: '' - 翻译: '这个方法会告诉 CMMotionManager 开始更新运动数据。' -- 内容: 'This property stores code that runs when the MotionDetector updates its motion data. If you want to execute custom actions every time the motion data changes, you can put your own code into onUpdate in your instance of MotionDetector.' - 提示: '' - 翻译: '这个属性存储了当 MotionDetector 更新其运动数据时需要运行的代码。如果你想在每次运动数据发生变化时执行自定义操作,你可以将自己的代码放到 MotionDetector 的 onUpdate 中。' -- 内容: 'Here is the value for the roll of the device, presented as text.' +- 内容: 'Step 23' 提示: '' - 翻译: '这里是设备的翻滚角的值,以文本形式呈现。' -- 内容: 'Step 13' + 翻译: '' +- 内容: 'There are four other lines on the edge of the frame of the bubble level display. You can use the .position modifier to move them relative to their default position at the center of the overlay view.' 提示: '' 翻译: '' -- 内容: 'Step 4' +- 内容: 'Double Extension' 提示: '' 翻译: '' -- 内容: 'Step 9' +- 内容: 'Investigate using an extension on Double to format them in an easy to read way.' 提示: '' 翻译: '' -- 内容: 'You can use a .frame modifier to give the circle a fixed width and height, which is important to draw the other components correctly.' +- 内容: 'An extension is a way to make custom behavior for existing types. Declaring extension Double means you’re adding new capabilities to the Double type. Any time you use a Double value in your code, you can access anything defined in this extension.' 提示: '' 翻译: '' -- 内容: 'Step 14' +- 内容: 'This method returns a string describing the value of a Double using a fixed number of digits. You can pass in the number of integer digits and fraction digits you want, or leave those arguments out for the default values of 2.' 提示: '' 翻译: '' -- 内容: 'Step 1' +- 内容: 'The formatted() method operates on a number of basic types such as Date, Int, and Double, which are all commonly represented as strings in an app. Because there are so many ways to format these strings, the formatted() method gives you ways to customize how they’re represented. For example, does a number represent a percentage, or a simple value, or maybe a price?' 提示: '' 翻译: '' -- 内容: 'Step 15' +- 内容: 'The argument to formatted() is a format style.' 提示: '' 翻译: '' -- 内容: 'Here’s a circle with a gray foreground color that provides a visual boundary for the display.' +- 内容: 'The .number style gives you a string describing this Double value as a simple number, as opposed to a percentage or a price.' 提示: '' 翻译: '' -- 内容: 'Step 21' +- 内容: 'The .number style has modifiers much like those for SwiftUI views.' 提示: '' 翻译: '' -- 内容: 'These properties have a @Published property wrapper, which means that any SwiftUI view that depends on their values updates when they change. You make a view dependent on a published property by referring to it in the view’s code. The BubbleLevel, LevelView, and OrientationDataView views use these properties, which enables them to update when the MotionDetector detects a change to the roll, pitch, or zAcceleration values.' +- 内容: 'The .sign modifier lets you format the number so that it’s always preceded by a sign, even when the number is positive.' 提示: '' - 翻译: '这些属性有一个 @Published 属性包装器,这意味着任何依赖于它们值的 SwiftUI 视图会在它们改变时更新。你可以通过在视图的代码中引用它来使视图依赖于已发布的属性。BubbleLevel、LevelView 和 OrientationDataView 视图使用这些属性,这使它们能够在 MotionDetector 检测到 roll、pitch 或 zAcceleration 值的变化时更新。' -- 内容: 'Present dynamic data in custom views.' + 翻译: '' +- 内容: 'The .precision modifier lets you specify exactly how many digits to use.' 提示: '' 翻译: '' -- 内容: 'The formatted() method operates on a number of basic types such as Date, Int, and Double, which are all commonly represented as strings in an app. Because there are so many ways to format these strings, the formatted() method gives you ways to customize how they’re represented. For example, does a number represent a percentage, or a simple value, or maybe a price?' +- 内容: 'Seismometer' 提示: '' 翻译: '' -- 内容: 'This view displays the tilt of your device by drawing a circle within a larger circular boundary with crosshairs to indicate its centerpoint. When your device is level, the bubble rests at the center of the frame. Try tilting your device to see how the bubble moves.' +- 内容: 'Present dynamic data in custom views.' 提示: '' 翻译: '' diff --git a/project/sample-apps/recognizinggestures.yml b/project/sample-apps/recognizinggestures.yml index d0e41ee..a7bad6e 100644 --- a/project/sample-apps/recognizinggestures.yml +++ b/project/sample-apps/recognizinggestures.yml @@ -1,4 +1,3 @@ -# TODO - 内容: 'Recognizing Gestures' 提示: '' 翻译: '' diff --git a/project/sample-apps/seismometer.yml b/project/sample-apps/seismometer.yml index 92951f9..d32d591 100644 --- a/project/sample-apps/seismometer.yml +++ b/project/sample-apps/seismometer.yml @@ -1,4 +1,3 @@ -# TODO - 内容: 'Seismometer' 提示: '' 翻译: '' From b6dd35b4b3b580c914195d5d1947e96f86a7538b Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 12:02:40 +0800 Subject: [PATCH 4/9] feat: bubble level done --- project/sample-apps/bubblelevel.yml | 80 ++++++++++++++--------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/project/sample-apps/bubblelevel.yml b/project/sample-apps/bubblelevel.yml index fd6b19c..9237287 100644 --- a/project/sample-apps/bubblelevel.yml +++ b/project/sample-apps/bubblelevel.yml @@ -159,136 +159,136 @@ 翻译: '这个属性会持有一个 MotionDetector 实例。运动检测器会感知你的设备运动的变化,并为你提供这些数据,以便你在代码中使用。' - 内容: 'Because detector is an observable object, any changes made to its published values cause SwiftUI to automatically update any views using those values. In this case, changes from the device’s sensors update the Text view with the latest values for the pitch and roll.' 提示: '' - 翻译: '因为 detector 是一个可观察对象,所以对它的 published 值所做的任何更改都会导致 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,来自设备传感器的更改会使用最新的俯仰角和翻滚角的值更新 Text 视图上的字符。' + 翻译: '因为 detector 是一个可观察对象,所以对它的 published 值所做的任何更改都会导致 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,来自设备传感器的更改会使用最新的 roll 和 pitch 的值更新 Text 视图上的字符。' - 内容: 'These two computed properties provide the strings used in the view. They take the roll or pitch value from the motion detector and format that number as a string with a fixed number of digits. The describeAsFixedLengthString() method is a custom method on the Double type. You can learn how it works in DoubleExtension.swift.' 提示: '' - 翻译: '这两个计算属性提供了视图中使用的字符串。它们从 motion detector 中获取翻滚角或俯仰角的值,并将该数字格式化为具有固定位数的字符串。describeAsFixedLengthString() 方法是 Double 类型的自定义方法。你可以在 DoubleExtension.swift 中了解它的工作原理。' + 翻译: '这两个计算属性提供了视图中使用的字符串。它们从 motion detector 中获取 roll 或 pitch 的值,并将该数字格式化为具有固定位数的字符串。describeAsFixedLengthString() 方法是 Double 类型的自定义方法。你可以在 DoubleExtension.swift 中了解它的工作原理。' - 内容: 'Here is the value for the roll of the device, presented as text.' 提示: '' 翻译: '这里是设备的翻滚角的值,以文本形式呈现。' - 内容: 'Because this view uses a published value from detector, SwiftUI updates it any time the motion detector’s roll value changes.' 提示: '' - 翻译: '因为这个视图使用了 detector 的一个 published value,所以 SwiftUI 会在运动检测器的翻滚角的值发生变化时更新它。' + 翻译: '因为这个视图使用了 detector 的一个 published value,所以 SwiftUI 会在 detecotr 的 roll 值发生变化时更新它。' - 内容: 'The .font modifier formats this Text view with a monospaced font. By default, a Text view uses a system font with proportional width, but that causes the text view to change its width as the numbers change.' 提示: '' - 翻译: '.font 装饰器使用等宽字体格式化这个 Text 视图。默认情况下,Text 视图使用系统字体,它的宽度是比例宽度,但这会导致 Text 视图在数字变化时改变它的宽度。' + 翻译: '.font 修饰符使用等宽字体格式化这个 Text 视图。默认情况下,Text 视图使用系统字体,它的宽度是比例宽度,但这会导致 Text 视图在数字变化时改变它的宽度。' - 内容: 'With a monospaced font, each character has the same width. (For example, the strings 1.01 and 3.14 have different widths with a proportional font like Helvetica or Times, but 1.01 and 3.14 have the same width with a monospaced font like Courier or Menlo.)' 提示: '' 翻译: '在等宽字体下,每个字符的宽度都是相同的。(例如,1.01 和 3.14 这两个字符串在 Helvetica 或 Times 等比例字体下的宽度是不同的,但在 Courier 或 Menlo 等等宽字体下,1.01 和 3.14 的宽度是相同的。)' - 内容: 'Bubble Level View' 提示: '' - 翻译: '' + 翻译: '泡泡水平仪.pre视图' - 内容: 'Learn to display the tilt of your device using a bubble level UI.' 提示: '' - 翻译: '学习如何使用气泡水平仪的 UI 来显示设备的倾斜。' + 翻译: '学习何使用 气泡水平仪的 UI 来显示设备的倾斜。' - 内容: 'This view displays the tilt of your device by drawing a circle within a larger circular boundary with crosshairs to indicate its centerpoint. When your device is level, the bubble rests at the center of the frame. Try tilting your device to see how the bubble moves.' 提示: '' - 翻译: '' + 翻译: '这个在自定义视图通过在一个较大的圆形边界内绘制一个圆圈,并用十字线来指示它的中心点,来显示你的设备的倾斜。当你的设备水平时,气泡会停留在框架的中心。试着倾斜你的设备,看看气泡是如何移动的。' - 内容: 'This property holds a MotionDetector instance, which senses changes in your device’s motion. You can access this instance in your code to update the user interface as the motion data changes.' 提示: '' - 翻译: '' + 翻译: '这个属性持有一个 MotionDetector 实例,它可以感知你的设备运动的变化。你可以在你的代码中访问这个实例,以便在运动数据发生变化时更新用户界面。' - 内容: 'Because detector is an observable object, any changes to its published values allows SwiftUI to automatically update any views using those values. In this case, you’ll update the bubble’s position.' 提示: '' 翻译: '因为 detector 是一个可观察对象,所以任何对它的 published 值的更改都会使 SwiftUI 自动更新使用这些值的任何视图。在这种情况下,你将更新气泡的位置。' - 内容: 'This property represents the range of values the motion detector reports as you tilt the device (assuming you don’t turn it upside down). Negative values indicate a tilt to the left, and positive values indicate a tilt to the right. (You could assign the value 3.14 to this property, but Double.pi is convenient shorthand for the mathematical constant π, and it’s a closer approximation because it includes many digits of precision.)' 提示: '' - 翻译: '' + 翻译: '这个属性表示运动检测器在你倾斜设备时报告的值的范围(假设你没有把它倒过来)。负值表示向左倾斜,正值表示向右倾斜。(你可以给这个属性赋值 3.14,但 Double.pi 是数学常量 π 的方便简写,它是一个更接近的近似值,因为它的精度更高。)' - 内容: 'This is the size of the level display, both width and height. You can change this value to make the display larger or smaller.' 提示: '' - 翻译: '' + 翻译: '这就是水平仪显示的大小,宽度和高度。你可以改变这个值来使其显示得更大或更小。' - 内容: 'It’s useful to define and use constants like these for important values in your code, rather than using the values themselves. When you read the code, you’ll have a better idea of what it does than if you see a lot of numbers with no context.' 提示: '' - 翻译: '' + 翻译: '比起来直接使用这些值,定义和使用这样的常量来表示代码中的重要值更有用。当你阅读代码时,看到这样的常量通常比看到一堆没有上下文的数字更容易理解它的作用。' - 内容: 'This property calculates the horizontal placement of the bubble using three steps.' 提示: '' - 翻译: '' + 翻译: '这个属性使用三个步骤来计算气泡的水平位置。' - 内容: 'First, adjust the roll value from the detector so that it has a minimum of 0 and goes up to the value of π, and store the adjusted value in zeroBasedRoll. This helps with the next part of the calculation, which needs values greater than 0.' 提示: '' - 翻译: '' + 翻译: '首先,调整检测器的 roll 值,使其最小值为 0,最大值为 π,并将调整后的值存储在 zeroBasedRoll 中。这有助于下一部分的计算,该计算需要大于 0 的值。' - 内容: 'Then, use this adjusted value to calculate the roll as a fraction of the entire range of roll values, so that full tilt left is 0.0, flat is 0.5, and full tilt right is 1.0.' 提示: '' - 翻译: '' + 翻译: '接下来,使用这个调整后的值来计算 roll 作为整个 roll 值范围的一个分数,这样完全向左倾斜就是 0.0,水平就是 0.5,完全向右倾斜就是 1.0。' - 内容: 'Multiplying the fraction with the size of the level gives you the X position of the bubble.' 提示: '' - 翻译: '' + 翻译: '将这个分数乘以水平仪的大小,就得到了气泡的 X 位置。' - 内容: 'Because all of these calculations are hidden in a property, your view’s body code remains simple and readable.' 提示: '' - 翻译: '' + 翻译: '因为所有这些计算都隐藏在一个属性中,所以你的视图的 body 代码保持简单和可读。' - 内容: 'While you can write all of the code here in a longer mathematical expression, decomposing the code makes it easier to understand. (Can you imagine having to explain this code if it were written in one line?!)' 提示: '' - 翻译: '' + 翻译: '虽然你可以在这里写所有的代码,但是把代码分解开来会更容易理解。(你能想象如果这段代码写在一行里,你要怎么解释这段代码吗?!)' - 内容: 'This property calculates the vertical position of the bubble in the same way that bubbleXPosition works.' 提示: '' - 翻译: '' + 翻译: '这个属性以与 bubbleXPosition 相同的方式计算气泡的垂直位置。' - 内容: 'This property returns a vertical line that you use to draw the bubble level display. Because there are multiple identical vertical lines, you can use this property whenever you need one rather than repeating the more complex code inside it.' 提示: '' - 翻译: '' + 翻译: '这个属性返回一个垂直线,你可以用它来绘制气泡水平仪的显示。因为有多个相同的垂直线,所以你可以在需要一个垂直线时使用这个属性,而不是重复其中的更复杂的代码。' - 内容: 'Here’s a circle with a gray foreground color that provides a visual boundary for the display.' 提示: '' - 翻译: '' + 翻译: '这里是一个圆,它有一个灰色的前景色,为显示提供了一个视觉边界。' - 内容: 'You can use a .frame modifier to give the circle a fixed width and height, which is important to draw the other components correctly.' 提示: '' - 翻译: '' + 翻译: '你可以使用 .frame 修饰符给圆一个固定的宽度和高度,这对于正确绘制其他组件很重要。' - 内容: 'The .overlay modifier adds a view on top of the circle that occupies the same area.' 提示: '' - 翻译: '' + 翻译: '.overlay 修饰符在圆上面添加一个视图,该视图占用相同的区域。' - 内容: 'The overlay is useful here because it positions the level’s components relative to the circle they’re drawn in.' 提示: '' - 翻译: '' + 翻译: 'overlay 在这里很有用,因为它将水平仪的组件相对于它们绘制的圆进行定位。' - 内容: 'A ZStack view allows you to draw the components of the level over each other.' 提示: '' - 翻译: '' + 翻译: '一个 ZStack .pre视图允许你将水平仪的组件绘制在彼此上面。' - 内容: 'The first circle represents the bubble. Notice that the bubbleXPosition and bubbleYPosition values position the bubble inside the overlay view.' 提示: '' - 翻译: '' + 翻译: '第一个代表气 泡。注意,bubbleXPosition 和 bubbleYPosition 值将气泡定位在覆盖视图内。' - 内容: 'Because these properties use published values from MotionDetector, SwiftUI updates the bubble view’s position each time they change.' 提示: '' - 翻译: '' + 翻译: '因为这在自定义些属性使用了 MotionDetector 的 published 值,所以 SwiftUI 在每次它们改变时都会更新气泡视图的位置。' - 内容: 'Step 22' 提示: '' 翻译: '' - 内容: 'In the center are a smaller circle and a crosshair made of two lines: one horizontal and one vertical.' 提示: '' - 翻译: '' + 翻译: '在中心是一个较小的圆和一个由两条线组成的十字线:一条水平线和一条垂直线。' - 内容: 'Step 23' 提示: '' 翻译: '' - 内容: 'There are four other lines on the edge of the frame of the bubble level display. You can use the .position modifier to move them relative to their default position at the center of the overlay view.' 提示: '' - 翻译: '' + 翻译: '这里还有其他四条线在气泡水平仪显示的边框上。你可以使用 .position 修饰符将它们相对于它们在覆盖视图中心的默认位置移动。' - 内容: 'Double Extension' 提示: '' - 翻译: '' + 翻译: '给 Double 类型增加扩展' - 内容: 'Investigate using an extension on Double to format them in an easy to read way.' 提示: '' - 翻译: '' + 翻译: '研究使用 Double 的扩展以一种易于阅读的方式格式化它们。' - 内容: 'An extension is a way to make custom behavior for existing types. Declaring extension Double means you’re adding new capabilities to the Double type. Any time you use a Double value in your code, you can access anything defined in this extension.' 提示: '' - 翻译: '' + 翻译: '扩展是为现有类型添加自定义行为的一种方式。声明扩展 Double 意味着你正在为 Double 类型添加新的功能。任何时候你在代码中使用 Double 值,你都可以访问在这个扩展中定义的任何东西。' - 内容: 'This method returns a string describing the value of a Double using a fixed number of digits. You can pass in the number of integer digits and fraction digits you want, or leave those arguments out for the default values of 2.' 提示: '' - 翻译: '' + 翻译: '这个方法返回一个字符串,描述一个 Double 的值,使用固定数量的数字。你可以传入你想要的整数位数和小数位数,或者忽略这些参数,使用默认值 2。' - 内容: 'The formatted() method operates on a number of basic types such as Date, Int, and Double, which are all commonly represented as strings in an app. Because there are so many ways to format these strings, the formatted() method gives you ways to customize how they’re represented. For example, does a number represent a percentage, or a simple value, or maybe a price?' 提示: '' - 翻译: '' + 翻译: 'formatted() 方法对一些基本类型进行操作,比如 Date、Int 和 Double,它们在应用中都通常表示为字符串。因为有很多方法可以格式化这些字符串,所以 formatted() 方法提供了一些方法来自定义它们的表示方式。例如,一个数字代表一个百分比,还是一个简单的值,或者一个价格?' - 内容: 'The argument to formatted() is a format style.' 提示: '' - 翻译: '' + 翻译: 'formatted() 的参数是一个 format style。' - 内容: 'The .number style gives you a string describing this Double value as a simple number, as opposed to a percentage or a price.' 提示: '' - 翻译: '' + 翻译: '.number style 给你一个字符串,描述这个 Double 值作为一个简单的数字,而不是一个百分比或一个价格。' - 内容: 'The .number style has modifiers much like those for SwiftUI views.' 提示: '' - 翻译: '' + 翻译: '.number style 有类似于 SwiftUI 视图的修饰符。' - 内容: 'The .sign modifier lets you format the number so that it’s always preceded by a sign, even when the number is positive.' 提示: '' - 翻译: '' + 翻译: '.sign 修饰符让你可以格式化数字,这样即使数字是正数,它也总是以一个符号开头。' - 内容: 'The .precision modifier lets you specify exactly how many digits to use.' 提示: '' - 翻译: '' + 翻译: '.precision 修饰符让你可以指定要使用多少位数字。' - 内容: 'Seismometer' 提示: '' - 翻译: '' + 翻译: '地震仪' - 内容: 'Present dynamic data in custom views.' 提示: '' - 翻译: '' + 翻译: '在自定义视图中呈现动态数据。' From b0efe2f4644b7666086574c9ced5c7e9bb4996b9 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 18:57:05 +0800 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=E5=9C=B0=E9=9C=87=E4=BB=AA?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project/sample-apps/seismometer.yml | 160 ++++++++++++++-------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/project/sample-apps/seismometer.yml b/project/sample-apps/seismometer.yml index d32d591..52519de 100644 --- a/project/sample-apps/seismometer.yml +++ b/project/sample-apps/seismometer.yml @@ -1,24 +1,24 @@ - 内容: 'Seismometer' 提示: '' - 翻译: '' + 翻译: '地震仪' - 内容: 'Present dynamic data in custom views.' 提示: '' - 翻译: '' + 翻译: '在自定义视图中呈现动态数据。' - 内容: 'Welcome to Seismometer.' 提示: '' - 翻译: '' + 翻译: '欢迎来到地震仪。' - 内容: 'You can use your iPad to detect vibrations using its built-in motion sensors. This sample shows how to display vibration information in two formats: a needle and a line graph.' 提示: '' - 翻译: '' + 翻译: '你可以使用 iPad 内置的运动传感器来检测震动。这个例子会向你展示如何用两种方式来展示震动:针形图和线形图' - 内容: 'Try out Seismometer by placing your iPad on a flat surface and then jostling it a bit. Or you can hold your iPad and move it up and down slowly.' 提示: '' - 翻译: '' + 翻译: '你可以将你的 iPad 放在一个平坦的平面上,然后稍微推挤一下来体验“地震仪”这个 App。或者,你可以拿着你的 iPad 慢慢地上下移动。' - 内容: 'Motion Detector' 提示: '' 翻译: '' - 内容: 'You can use the MotionDetector class to observe the motion of your device.' 提示: '' - 翻译: '' + 翻译: '你可以使用 MotionDetector 类来观察你的设备的运动。' - 内容: 'Step 1' 提示: '' 翻译: '' @@ -27,265 +27,265 @@ 翻译: '' - 内容: 'A CMMotionManager is the object that you use to get motion data from the sensors in your iPad, such as the accelerometer. It gathers information from the sensors and translates their data into values you can understand.' 提示: '' - 翻译: '' + 翻译: 'CMotionManager 是你用来从你的 iPad 的传感器中获取运动数据的对象,比如加速度计。它会从传感器中收集信息,并将它们的数据转换成你可以理解的值。' - 内容: 'Step 3' 提示: '' 翻译: '' - 内容: 'The timer property stores a Timer instance. A timer waits for certain period of time, defined in the updateInterval property, before running some code. The MotionDetector uses the timer to update its pitch, roll, and zAcceleration values at regular intervals.' 提示: '' - 翻译: '' + 翻译: 'timer 属性存储了一个 Timer 实例。Timer 会在一段时间后——即 updateInterval 属性中定义的时间后,运行一些代码。MotionDetector 使用 timer 来在固定的时间间隔内更新它的 pitch、roll 和 zAcceleration 值。' - 内容: 'Note' 提示: '' - 翻译: '' + 翻译: '注意' - 内容: 'Choose an update interval that makes sense for your app. For example, you’ll want a short update interval for the seismometers in this project because the interface presents real-time data as you move your iPad around.' 提示: '' - 翻译: '' + 翻译: '选择一个对你的 App 来说有意义的更新间隔。例如,你会想要一个短的更新间隔,因为这个项目中的地震仪会在你移动你的 iPad 时实时更新数据。' - 内容: 'Step 4' 提示: '' 翻译: '' - 内容: 'These three properties store data for the tilt of your device in two dimensions (roll and pitch), as well as its vertical acceleration (zAcceleration).' 提示: '' - 翻译: '' + 翻译: '这三个属性存储了你的设备在两个维度上的倾斜(roll 和 pitch),以及它的垂直加速度(zAcceleration)。' - 内容: 'These properties have a @Published property wrapper, which means that any SwiftUI view that depends on their values automatically updates when the values change. You make a view dependent on a published property by using that value in the view’s code. The NeedleSeismometer and GraphSeismometer samples use these properties to update when the MotionDetector detects changes to the values of roll, pitch, and zAcceleration.' 提示: '' - 翻译: '' + 翻译: '这些属性有一个 @Published 属性包装器,这意味着任何依赖于它们值的 SwiftUI 视图在值改变时会自动更新。你可以通过在视图的代码中使用该值来使视图依赖于已发布的属性。NeedleSeismometer 和 GraphSeismometer 示例会使用这些属性来在 MotionDetector 检测到 roll、pitch 和 zAcceleration 值的变化时更新。' - 内容: 'Step 5' 提示: '' 翻译: '' - 内容: 'This property stores code that runs when the MotionDetector updates its motion data. If you want to execute custom actions when the motion data changes, you can put your own code into onUpdate in your instance of MotionDetector.' 提示: '' - 翻译: '' + 翻译: '这个属性存储了 MotionDetector 更新它的运动数据时要运行的代码。如果你想在运动数据改变时执行自定义操作,你可以将你自己的代码放到 MotionDetector 的 onUpdate 中。' - 内容: 'Step 6' 提示: '' 翻译: '' - 内容: 'This method starts updating the motion detector.' 提示: '' - 翻译: '' + 翻译: '这个方法开始更新运动检测器。' - 内容: 'Step 7' 提示: '' 翻译: '' - 内容: 'Always use isDeviceMotionAvailable to verify that motion data is available before you try to access it.' 提示: '' - 翻译: '' + 翻译: '当你在尝试访问它之前,总是使用 isDeviceMotionAvailable 来验证运动数据是否可用。' - 内容: 'Step 8' 提示: '' 翻译: '' - 内容: 'This method tells the CMMotionManager to start updating motion data.' 提示: '' - 翻译: '' + 翻译: '这个方法告诉 CMMotionManager 开始更新运动数据。' - 内容: 'Step 9' 提示: '' 翻译: '' - 内容: 'This code creates a new timer and schedules it to run. The updateInterval property tells the timer how long to wait between updates, and repeats is set to true so the timer runs forever until you stop it. (If you pass false to repeats, the timer only runs once.) The block of code at the end of the line that reads { _ in is the start of a closure that contains the code run by the timer. The closure calls the updateMotionData() method.' 提示: '' - 翻译: '' + 翻译: '这段代码创建了一个新的计时器,并设定了它调用的时机。updateInterval 属性会告诉计时器在更新之间等待多长时间,由于 repeats 被设置为 true,因此计时器会一直运行,直到你停止它(如果你传递 false 给 repeats,计时器只会运行一次。)。 行末尾的代码块 { _ in 计时器会调用的闭包的开始部分。在这个闭包中,代码调用了 updateMotionData() 方法。' - 内容: 'Step 10' 提示: '' 翻译: '' - 内容: 'The updateMotionData() method does the core work of the motion detector. It’s responsible for updating all published properties with current data from the sensors, as well as calling the code in onUpdate.' 提示: '' - 翻译: '' + 翻译: 'updateMotionData() 方法完成了是运动检测器的核心工作。它负责使用传感器的当前数据更新所有已发布的属性,以及调用 onUpdate 方法。' - 内容: 'Step 11' 提示: '' 翻译: '' - 内容: 'The deviceMotion data may not be there in certain conditions. To see if the data exists, try to assign deviceMotion to a variable or constant using if let. If the motion data exists, it’s assigned to data and the code inside the braces runs. Otherwise, it skips the entire if statement.' 提示: '' - 翻译: '' + 翻译: 'deviceMotion 数据在某些情况下可能不存在。要查看数据是否存在,请尝试使用 if let 将 deviceMotion 分配给变量或常量。如果运动数据存在,它就会被分配给 data,然后花括号内的代码就会运行。否则,它就会跳过整个 if 语句。' - 内容: 'Step 12' 提示: '' 翻译: '' - 内容: 'A CMDeviceMotion instance represents device motion, stored in data. The CMDeviceMotion class has quite a few properties for describing the input from the motion sensors. Use the attitude property to get the device’s tilt in three directions. You may be familiar with X, Y, and Z axes in 3D space, which relate to pitch, roll, and yaw, respectively.' 提示: '' - 翻译: '' + 翻译: 'CMDeviceMotion 实例表示设备运动状态,存储在 data 属性中。CMDeviceMotion 类有很多属性来描述运动传感器的输入。使用 attitude 属性来获取设备在三个方向上的倾斜。你可能熟悉 3D 空间中的 X、Y 和 Z 轴,它们分别与 pitch、roll 和 yaw 相关。' - 内容: 'Step 13' 提示: '' 翻译: '' - 内容: 'Use the userAcceleration property to get the device’s acceleration after accounting for the downward pull of gravity. If your device is still, this number is 0. However, the value changes to a negative number when you lift your iPad upward, or to a positive number when you move your iPad downward.' 提示: '' - 翻译: '' + 翻译: '使用 userAcceleration 属性来获取设备在考虑到重力向下拉的情况下的加速度。如果你的设备静止不动,这个数值就是 0。然而,当你将 iPad 向上抬起时,这个值会变成一个负数,或者当你将 iPad 向下移动时,这个值会变成一个正数。' - 内容: 'Step 14' 提示: '' 翻译: '' - 内容: 'You run the code in onUpdate just as you’d call any function, with a set of parentheses following its name.' 提示: '' - 翻译: '' + 翻译: '你可以像调用任何函数一样调用 onUpdate 中的代码,只需要在函数名后面加上一对括号。' - 内容: 'Step 15' 提示: '' 翻译: '' - 内容: 'The stop() method tells the CMMotionManager class to stop updating its values by calling stopDeviceMotionUpdates(), then it stops the timer by calling invalidate().' 提示: '' - 翻译: '' + 翻译: 'stop() 方法通过调用 stopDeviceMotionUpdates() 告诉 CMMotionManager 类停止更新它的值,然后它通过调用 invalidate() 停止计时器。' - 内容: 'Step 16' 提示: '' 翻译: '' - 内容: 'This deinitializer runs when a MotionDetector instance is about to go away. It’s important to clean up here; otherwise the timer continues to run even after the motion detector is gone.' 提示: '' - 翻译: '' + 翻译: '这个析构器在 MotionDetector 实例即将消失时运行。在这里做一些善后工作很重要;否则,即使 motion detector 对象消失了,计时器仍然会继续运行。' - 内容: 'Needle Seismometer' 提示: '' - 翻译: '' + 翻译: '指针地震仪' - 内容: 'Learn how to display a needle that registers the vibration of your device.' 提示: '' - 翻译: '' + 翻译: '学习如何显示一个可以记录你的设备振动的指针。' - 内容: 'The NeedleSeismometer view displays a needle that moves as your device vibrates. It uses the zAcceleration data from a MotionDetector instance to detect vibration, and translates that data into left and right rotation of the needle.' 提示: '' - 翻译: '' + 翻译: 'NeedleSeismometer 视图显示一个随着你的设备振动而移动的指针。它使用 MotionDetector 实例的 zAcceleration 数据来检测振动,并将这些数据转换为指针的左右旋转。' - 内容: 'The motionDetector property holds a MotionDetector instance. The motion detector senses changes in your device’s motion and provides that data for use in your code.' 提示: '' - 翻译: '' + 翻译: 'motionDetector 属性保存一个 MotionDetector 实例。运动检测器会感知你的设备运动的变化,并提供这些数据供你在代码中使用。' - 内容: 'The property has an @EnvironmentObject property wrapper because this view expects the app to put a motion detector in the environment for it to use.' 提示: '' - 翻译: '' + 翻译: '该属性有一个 @EnvironmentObject 属性包装器,因为该视图期望应用程序将一个运动检测器放在环境中供它使用。' - 内容: 'The seismometer display is a vertical stack (VStack) with a rotating needle, text that displays the raw values from the sensor, and some instructions for people to follow.' 提示: '' - 翻译: '' + 翻译: '地震仪显示是一个垂直堆栈(VStack),有一个旋转的指针,一个显示传感器原始值的文本,以及一些人们要遵循的指示。' - 内容: 'You can use a ZStack to layer views on top of each other. Here, the background view for the gauge goes underneath the needle itself. The background draws a semicircle with marks around its edge. Check out the code in GaugeBackground.swift if you’re curious how that’s done.' 提示: '' - 翻译: '' + 翻译: '你可以使用 ZStack 将视图层叠在一起。在这里,仪表盘的背景视图位于指针本身的下方。背景绘制了一个带有标记的半圆。如果你想知道这是怎么做的,请查看 GaugeBackground.swift 中的代码。' - 内容: 'The needle is just a rectangle with a .frame modifier to give it a narrow, tall shape. It also uses the .foregroundColor modifier to adopt the app’s accent color. Try changing the accent color of this sample to see how it affects the view.' 提示: '' - 翻译: '' + 翻译: '指针只是一个矩形,有一个 .frame 修饰符,给它一个狭窄的、高的形状。它还使用 .foregroundColor 修饰符来采用应用程序的强调颜色。尝试更改此示例的强调颜色,看看它如何影响视图。' - 内容: 'Use the .rotationEffect modifier to rotate the rectangle for the needle, and set the rotationAngle and needleAnchor properties to define the needle’s behavior. You pass in rotationAngle as the first argument, which interprets the motion data to calculate the correct needle angle.' 提示: '' - 翻译: '' + 翻译: '使用 .rotationEffect 修饰符来旋转指针的矩形,并设置 rotationAngle 和 needleAnchor 属性来定义指针的行为。你将 rotationAngle 作为第一个参数传入,它会解释运动数据来计算正确的指针角度。' - 内容: 'By default, rotation happens around the center of a view; however, you can use the needleAnchor property as the second argument so the needle rotates at its base.' 提示: '' - 翻译: '' + 翻译: '默认情况下,旋转发生在视图的中心;然而,你可以使用 needleAnchor 属性作为第二个参数,这样指针就会在它的底部旋转。' - 内容: 'The rotationAngle property returns the amount the needle rotates for a given sensor reading. The rotationEffect property expects an Angle instance, so you can create one using the zAcceleration property of the motion detector. The motion detector represents upward acceleration with a negative number, but you’re multiplying by -1 to make upward acceleration positive, and downward acceleration negative.' 提示: '' - 翻译: '' + 翻译: 'rotationAngle 属性返回指针在给定传感器读数下旋转的量。rotationEffect 属性期望一个 Angle 实例,所以你可以使用运动检测器的 zAcceleration 属性创建一个。运动检测器用一个负数表示向上的加速度,但是你乘以 -1 来使向上的加速度为正,向下的加速度为负。' - 内容: 'Experiment' 提示: '' - 翻译: '' + 翻译: '实验' - 内容: 'The amplification constant is useful for controlling the sensitivity of the display. Try changing its value to see how that affects the needle.' 提示: '' - 翻译: '' + 翻译: 'amplification 常量对于控制显示的灵敏度很有用。尝试更改它的值,看看它如何影响指针。' - 内容: 'The needleAnchor property defines the point of rotation for the needle as a UnitPoint. A unit point has x and y coordinates like a regular point, but their values only range between 0 and 1.' 提示: '' - 翻译: '' + 翻译: 'needleAnchor 属性将指针的旋转点定义为 UnitPoint。一个单位点有 x 和 y 坐标,就像一个普通的 point 类型,但它们的值只能取在 0 和 1 之间。' - 内容: 'A unit point is useful for defining a point inside any view, regardless of its size. This one defines the midpoint of a view (width-wise) at its bottom. Regardless of the view’s size, the point is exactly at that location relative to the view’s width and height.' 提示: '' - 翻译: '' + 翻译: '当我们不想关心视图的具体大小的时候,用 unit point 来定义视图内部的点会非常有用。在这里,这个 unit point 定义了视图的中点(宽度方向)在视图底部。无论具体视图的大小是多少,该点都恰好位于相对于视图宽度和高度的固定位置。' - 内容: 'Without this overlay, you’d get a plain rectangle that rotates at its base. But to make things a little more polished, this overlay adds a small circle at the bottom.' 提示: '' - 翻译: '' + 翻译: '如果没有这个 overlay,你就会得到一个在底部旋转的普通矩形。但是为了让矩形看起来更加精致,这个 overlay 在矩形底部添加了一个小圆。' - 内容: 'You can use an overlay to put content directly on top of a view. The overlay occupies the same area as its parent view. In this overlay, a Spacer pushes a small Circle to the bottom of a VStack so it aligns with the base of the needle.' 提示: '' - 翻译: '' + 翻译: '你可以使用 overlay 将内容直接放在视图的顶部。overlay 占据与其父视图相同的区域。在这个 overlay 中,一个 Spacer 将一个小圆推到 VStack 的底部,这样它就与指针的底部对齐了。' - 内容: 'Graph Seismometer' 提示: '' - 翻译: '' + 翻译: '图形化的地震仪' - 内容: 'Learn how to display the vibration of your device as an animated line graph.' 提示: '' - 翻译: '' + 翻译: '学习如何将你的设备的振动显示为一个动画的折线图。' - 内容: 'The GraphSeismometer view displays a line graph of your device’s vibration. It uses the zAcceleration data from a MotionDetector instance to detect vibration, and translates that data into Y values in the graph; the X values represent time.' - 提示: '' + 提示: 'GraphSeismometer 视图显示了你的设备的振动的折线图。它使用 MotionDetector 实例的 zAcceleration 数据来检测振动,并将该数据转换为图表中的 Y 值;X 值表示时间。' 翻译: '' - 内容: 'This property holds a MotionDetector instance. The motion detector senses changes in your device’s motion and provides that data for you to use in your code.' 提示: '' - 翻译: '' + 翻译: '这个属性保存了一个 MotionDetector 实例。它会感知你的设备运动的变化,并为你提供这些数据,以便你在代码中使用。' - 内容: 'The data property stores the seismometer data you’ll graph in this view as an array of Double values. It includes a @State property wrapper because you want the line graph to update whenever the data changes.' 提示: '' - 翻译: '' + 翻译: 'data 属性是一个值为 Double 的数组,它会存储地震仪的数据,并提供给你以便在视图中以图形形式呈现。因为你会希当数据变化时折线图也跟着变化,所以这个属性还包括了一个 @State 属性包装器。' - 内容: 'The maxData property represents the maximum number of data points your graph shows. This is vital, because the seismometer updates 100 times per second, which produces a lot of data, and you don’t want to keep that around forever. When you accumulate enough data, you’ll start deleting the old ones.' 提示: '' - 翻译: '' + 翻译: 'maxData 属性表示你的图表显示的数据点的最大数量。这是至关重要的,因为地震仪每秒更新 100 次,这会产生大量的数据,而你不希望永远保留这些数据。当你积累了足够的数据,你就会开始删除旧数据。' - 内容: 'The sensitivity property controls how sensitive the seismometer is to motion. Sensitivity affects the line graph by expanding it vertically. The higher the sensitivity, the larger the peaks and valleys will appear in the graph.' 提示: '' - 翻译: '' + 翻译: 'sensitivity 属性控制地震仪对运动的敏感度。敏感度会通过在垂直方向上扩展折线图来影响折线图。敏感度越高,图表中的峰值和谷值就会越大。' - 内容: 'The graphMaxValueMostSensitive property represents the maximum value the graph displays at its most sensitive, and graphMaxValueLeastSensitive represents the maximum value displayed at its least sensitive. Along with sensitivity, these properties control the graph’s display.' 提示: '' - 翻译: '' + 翻译: 'graphMaxValueMostSensitive 属性表示图表在最敏感时显示的最大值,graphMaxValueLeastSensitive 表示在最不敏感时显示的最大值。这些属性与敏感度一起控制图表的显示。' - 内容: 'Try changing these values to affect the range of sensitivity of the graph. (Note that graphMaxValueMostSensitive should always be less than graphMaxValueLeastSensitive.)' 提示: '' - 翻译: '' + 翻译: '尝试更改这些值以影响图表的敏感度范围。(注意,graphMaxValueMostSensitive 应该始终小于 graphMaxValueLeastSensitive。)' - 内容: 'This property represents the maximum value of the graph: the one that’s represented by the top edge. The calculation uses the sensitivity properties declared above.' 提示: '' - 翻译: '' + 翻译: '这个属性表示图表的最大值:也就是顶部边缘所代表的值。计算使用了上面声明的敏感度属性。' - 内容: 'The LineGraph.swift file represents the main view of the seismometer. The initializer for LineGraph has four parameters: the data to display, the maximum amount of data in the graph, and the minimum and maximum values corresponding to its bottom and top edges.' 提示: '' - 翻译: '' + 翻译: 'LineGraph.swift 文件表示地震仪的主视图。LineGraph 的初始化器有四个参数:要显示的数据、图表中的最大数据量,以及对应于其底部和顶部边缘的最小值和最大值。' - 内容: 'As you explore the seismometer, you’ll notice that the data can contain values outside the minimum and maximum range, but they aren’t displayed because they fall outside the view bounds.' 提示: '' - 翻译: '' + 翻译: '当你探索地震仪时,你会注意到数据可能包含在最小值和最大值范围之外的值,但它们不会被显示,因为它们超出了视图边界。' - 内容: 'These five modifiers configure the line graph display. The .clipped modifier prevents the line from drawing outside its frame. You can use .background to set the background color. By using .accentColor the display can adapt to your app’s theme. Using opacity makes the color less bold.' 提示: '' - 翻译: '' + 翻译: '这五个修饰符配置了折线图的显示。.clipped 修饰符防止线条在其框架之外绘制。你可以使用 .background 来设置背景颜色。通过使用 .accentColor,显示可以适应你的应用程序的主题。使用 opacity 使颜色不那么醒目。' - 内容: 'Try commenting out the .clipped modifier to see what happens with the graph display.' 提示: '' - 翻译: '' + 翻译: '尝试注释掉 .clipped 修饰符,看看图表显示会发生什么。' - 内容: 'You can curve the points of the graph by adding .cornerRadius to the line. Change the number to make the curves broader or narrower. The .padding modifier adds some space around the edges to keep it away from other views.' 提示: '' - 翻译: '' + 翻译: '你可以通过在线条上添加 .cornerRadius 来使图表的点变成曲线。更改数字可以使曲线变宽或变窄。.padding 修饰符在边缘周围添加了一些空间,使其远离其他视图。' - 内容: 'The modifier .aspectRatio gives it a square shape.' 提示: '' - 翻译: '' + 翻译: '.aspectRatio 修饰符使其呈正方形。' - 内容: 'Try changing the number to 2, or 0.3, to see how that affects the display.' 提示: '' - 翻译: '' + 翻译: '尝试将数字更改为 2 或 0.3,看看它如何影响显示。' - 内容: 'The Slider control affects the sensitivity of the graph display. Its first parameter, value: $sensitivity, is a binding to the sensitivity state property.' 提示: '' - 翻译: '' + 翻译: 'Slider 控件会影响图表显示的敏感度。它的第一个参数 value: $sensitivity 是对敏感度状态属性的绑定。' - 内容: 'You use bindings to let other views control state properties. In this case, you’re telling the slider it can update the value of sensitivity as the user interacts with it.' 提示: '' - 翻译: '' + 翻译: '你可以使用绑定来让其他视图控制状态属性。在当前场景中,你会在用户和滑块交互时告诉它可以更新 sensitivity 变量的值。' - 内容: 'The next three parameters control features of the slider. in: 0...1: specifies the slider’s range of values, from minimum to maximum. Use the minimumValueLabel and maximumValueLabel parameters to add labels at the left and right ends of the slider, respectively.' 提示: '' - 翻译: '' + 翻译: '接下来的三个参数控制滑块的特性。in: 0...1:指定滑块的值范围,从最小值到最大值。minimumValueLabel 和 maximumValueLabel 参数会分别在滑块的左端和右端添加标签。' - 内容: 'To store a history of motion values to draw the line graph, assign the code inside the braces to the onUpdate property. This tells the motion detector to run that code whenever there’s new data to display. This code takes the latest motion data and adds it to the data array.' 提示: '' - 翻译: '' + 翻译: '为了存储绘制折线图所需的运动值历史记录,将大括号内的代码分配给 onUpdate 属性。这会告诉运动检测器在有新数据要显示时运行该代码。该代码会获取最新的运动数据并将其添加到数据数组中。' - 内容: 'Append the zAcceleration of the device to the data array with every motion detector update. Use zAcceleration to chart up- and downward motion of the device. That makes the graph correspond visually to the movement of the device. When you lift your iPad, the line goes upward on the graph.' 提示: '' - 翻译: '' + 翻译: '每次 motion detector 更新时,设备的 zAcceleration 会被追加到 data 数组中。使用 zAcceleration 来绘制设备的上下运动。这使得图表在视觉上与设备的运动相对应。当你抬起 iPad 时,线条在图表上向上移动。' - 内容: 'Here’s where the maxData property comes into play. After you’ve reached the limit, you’ll drop the first item in the array (the oldest data point) and make a new array out of the result.' 提示: '' - 翻译: '' + 翻译: '这里就是 maxData 属性发挥作用的地方。在达到限制后,你将删除数组中的第一个项目(最旧的数据点),并将结果制作成一个新数组。' - 内容: 'Seismometer Browser' 提示: '' - 翻译: '' + 翻译: '地震仪浏览器' - 内容: 'Learn how the top-level view of the app passes motion data to its child views.' 提示: '' - 翻译: '' + 翻译: '学习如何将应用的顶级视图中的运动数据传递给其子视图。' - 内容: 'The SeismometerBrowser view displays the two options for seismometer display in a list. When you choose a display from the list, the app displays that view. The browser is a container for the other two views, so it also acts as the manager of the MotionDetector instance that gathers motion data from the device.' 提示: '' - 翻译: '' + 翻译: 'SeismometerBrowser 视图在列表中显示地震仪的两个选项。当你从列表中选择一个显示时,应用会显示该视图。浏览器是其他两个视图的容器,因此它也充当从设备收集运动数据的 MotionDetector 实例的管理器。' - 内容: 'The detector property holds the MotionDetector instance that’s shared throughout the app. The code annotates the property with @StateObject to indicate that SwiftUI keeps track of its updates. You can share state objects with other views, but this view is its owner.' 提示: '' - 翻译: '' + 翻译: 'detector 属性保存了在整个应用程序中共享的 MotionDetector 实例。代码使用 @StateObject 以指示 SwiftUI 会跟踪其更新。你可以与其他视图共享该属性,但是该视图是其所有者。' - 内容: 'To give other views access to the motion detector, you can use the .environmentObject modifier to add it to the app’s environment. Any child view of this view can use it by declaring a property of the same type and annotating it with @EnvironmentObject.' 提示: '' - 翻译: '' + 翻译: '为了让其他视图访问运动检测器,你可以使用 .environmentObject 修饰符将其添加到应用程序的环境中。该视图的任何子视图都可以通过声明具有相同类型的属性并使用 @EnvironmentObject 进行注释来使用它。' - 内容: 'You can use the .onAppear modifier to perform actions when this view first appears. It’s the perfect place to start the motion detector. Use the .onDisappear modifier to stop the detector when the view isn’t visible.' 提示: '' - 翻译: '' + 翻译: '你可以使用 .onAppear 修饰符在该视图首次出现时执行操作。这是启动运动检测器的理想位置。使用 .onDisappear 修饰符在视图不可见时停止检测器。' - 内容: 'Double Extension' 提示: '' - 翻译: '' + 翻译: 'Double 类型的扩展' - 内容: 'Investigate using an extension on Double to format text in an easy to read way.' 提示: '' - 翻译: '' + 翻译: '探究使用 Double 类型的扩展以便以易于阅读的方式格式化文本。' - 内容: 'You can use an extension to create custom behaviors for existing types. Declaring extension Double means you’re adding new capabilities to the Double type. When you use a Double value, you can access anything defined in this extension.' 提示: '' - 翻译: '' + 翻译: '你可以使用扩展为现有类型创建自定义行为。声明 Double 扩展意味着你正在为 Double 类型添加新功能。当你使用 Double 值时,可以访问在此扩展中定义的任何内容。' - 内容: 'This method returns a string that describes the value of a Double with a fixed number of digits. You can pass in the number of integer digits and fraction digits you want, or leave those arguments out for the default values of 2.' 提示: '' - 翻译: '' + 翻译: '这个方法返回一个字符串,该字符串用固定数量的数字描述 Double 的值。你可以传入你想要的整数位数和小数位数,或者忽略这些参数以使用默认值 2。' - 内容: 'The formatted() method operates on a number of basic types such as Date, Int, and Double, all of which are commonly represented as strings in an app. Because there are so many ways to format these strings, the formatted() method gives you ways to customize how they’re represented. For example, does a number represent a percentage, a simple value, or maybe a price?' 提示: '' - 翻译: '' + 翻译: 'formatted() 方法对许多基本类型(如 Date、Int 和 Double)进行操作,所有这些类型在应用程序中通常表示为字符串。因为有很多方法可以格式化这些字符串,所以 formatted() 方法提供了一些方法来自定义它们的表示方式。例如,一个数字表示一个百分比、一个简单的值,或者可能是一个价格?' - 内容: 'The argument to formatted() is a format style. The .number style gives you a string that describes this Double value as a simple number, as opposed to a percentage or a price.' 提示: '' - 翻译: '' + 翻译: 'formatted() 的参数是一个 format style 类型。.number 样式为你提供了一个字符串,该字符串将此 Double 值描述为一个简单的数字,而不是一个百分比或价格。' - 内容: 'The .number style has modifiers much like those for SwiftUI views. For example, the .sign modifier lets you format the number so that it’s always preceded by a sign, even when the number is positive. You can also use the .precision modifier to specify exactly how many digits to use.' 提示: '' - 翻译: '' + 翻译: '.number 这种变成风格具有与 SwiftUI 视图相似的修饰符。例如,.sign 修饰符允许你格式化数字,以便即使数字为正数,它也总是以符号开头。你还可以使用 .precision 修饰符来指定要使用的精度。' - 内容: 'Recognizing Gestures' 提示: '' - 翻译: '' + 翻译: '识别手势' - 内容: 'Update shapes or other content in response to taps, rotations, or other Multi-Touch gestures.' 提示: '' - 翻译: '' + 翻译: '当识别到点击、旋转或其他多点触控手势时,更新形状或其他内容。' - 内容: 'Your device has sensors such as accelerometers and gyroscopes which sense its motion and orientation. The Core Motion framework gives you access to data from these and other sensors.' 提示: '' - 翻译: '' + 翻译: '你的设备具有加速度计和陀螺仪等传感器,这些传感器可以感知其运动和方向。Core Motion 框架使你可以访问来自这些和其他传感器的数据。' From afebec1ac5fcf4cde551944c6156165414205021 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 19:31:35 +0800 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20gesture=20=E4=B8=80=E5=B0=8F?= =?UTF-8?q?=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project/sample-apps/recognizinggestures.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/project/sample-apps/recognizinggestures.yml b/project/sample-apps/recognizinggestures.yml index a7bad6e..c0543ff 100644 --- a/project/sample-apps/recognizinggestures.yml +++ b/project/sample-apps/recognizinggestures.yml @@ -1,27 +1,27 @@ - 内容: 'Recognizing Gestures' 提示: '' - 翻译: '' + 翻译: '识别手势' - 内容: 'Update shapes or other content in response to taps, rotations, or other Multi-Touch gestures.' 提示: '' - 翻译: '' + 翻译: '当识别到点击、旋转或其他多点触控手势时,更新形状或其他内容。' - 内容: 'Welcome to Recognizing Gestures. In this sample you’ll learn how to add different gestures to your views, like taps, drags, and touch and hold.' 提示: '' - 翻译: '' + 翻译: '欢迎来到识别手势。在本示例中,您将学习如何将不同的手势添加到视图中,例如点击、拖动和触摸并保持。' - 内容: 'Start by trying out each gesture in the app preview. When you’re ready, dive into the code walkthrough and learn how to add a gesture to your next project.' 提示: '' - 翻译: '' + 翻译: '你可以通过在预览窗口尝试各种手势来开始。当你准备好之后,就可以深入代码并在下一个项目中学习如何添加手势了' - 内容: 'Tap' 提示: '' - 翻译: '' + 翻译: '点击' - 内容: 'Explore how to apply different colors to a rectangle when tapped.' 提示: '' - 翻译: '' + 翻译: '探索如何在点击的时候给正方形赋予不同的颜色' - 内容: 'Step 1' 提示: '' 翻译: '' - 内容: 'In SwiftUI, you can add a gesture directly to a view using a .gesture modifier. Here, you’ll explore how to add a tap gesture to a rectangle view so that it changes color when pressed.' 提示: '' - 翻译: '' + 翻译: '在 SwiftUI 中,你可以' - 内容: 'Step 2' 提示: '' 翻译: '' From bf6e5bac0656e97bb3902dc540a767408a8e5225 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 21:13:55 +0800 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E6=89=8B?= =?UTF-8?q?=E5=8A=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project/sample-apps/recognizinggestures.yml | 98 ++++++++++----------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/project/sample-apps/recognizinggestures.yml b/project/sample-apps/recognizinggestures.yml index c0543ff..673b083 100644 --- a/project/sample-apps/recognizinggestures.yml +++ b/project/sample-apps/recognizinggestures.yml @@ -21,166 +21,166 @@ 翻译: '' - 内容: 'In SwiftUI, you can add a gesture directly to a view using a .gesture modifier. Here, you’ll explore how to add a tap gesture to a rectangle view so that it changes color when pressed.' 提示: '' - 翻译: '在 SwiftUI 中,你可以' + 翻译: '在 SwiftUI 中,你可以使用 .gesture 修饰符直接将手势添加到视图中。在这里,你将探索如何将点击手势添加到矩形视图中,以便在按下时更改颜色。' - 内容: 'Step 2' 提示: '' 翻译: '' - 内容: 'To set up this tap gesture, you need a @State value, color. When you mark the property with @State, SwiftUI updates all views that use this value any time it changes.' 提示: '' - 翻译: '' + 翻译: '为了设置这个点击手势,你需要一个用 @State 修饰的值,也就是这里的 color 属性。当你使用 @State 标记属性后,SwiftUI 会在该值变化后更新所有使用了这个值的视图' - 内容: 'Step 3' 提示: '' 翻译: '' - 内容: 'The color value is set as the foreground color of the rectangle. Whenever this value changes, the color of the rectangle updates.' 提示: '' - 翻译: '' + 翻译: 'color 变量用于设置矩形的前景色。矩形的颜色会在这个变量变化时更新' - 内容: 'Step 4' 提示: '' 翻译: '' - 内容: 'This code defines a custom gesture, tapGesture. After you’ve defined a custom gesture, you can attach it to a view using the .gesture modifier.' 提示: '' - 翻译: '' + 翻译: '这段代码定义了一个自定义的手势,点击手势。在你定义了自定义手势后,你就可以使用 .gesture 修饰符将其添加到一个视图上' - 内容: 'Step 5' 提示: '' 翻译: '' - 内容: 'Your custom gesture uses a TapGesture and defines the event handler for when the tap ends. When the tap ends, you assign a random value to color, and the rectangle automatically updates to reflect the new value.' 提示: '' - 翻译: '' + 翻译: '你的自定义手势使用了 TapGesture 类,并定义了一个点击结束时的事件处理器。当点击结束时,你会给 color 属性设置一个随机的值,并且矩形会自动更新以反映出 color 属性的新值。' - 内容: 'Step 6' 提示: '' 翻译: '' - 内容: 'By passing tapGesture into the .gesture modifier, the rectangle responds to taps using your custom gesture definition.' 提示: '' - 翻译: '' + 翻译: '通过将 tapGesture 传递给 .gesture 修饰符,矩形会使用你自定义的手势定义来响应点击。' - 内容: 'Long Press' 提示: '' - 翻译: '' + 翻译: '长按' - 内容: 'Touch and hold to change the shape of a capsule.' 提示: '' - 翻译: '' + 翻译: '触摸并保持以更改胶囊的形状。' - 内容: 'In the LongPressView, you’ll change the height and width of a capsule shape every time you touch and hold on the shape.' 提示: '' - 翻译: '' + 翻译: '在 LongPressView 中,你将在每次触摸并保持的时候更改胶囊形状的高度和宽度。' - 内容: 'To change the capsule’s size, you’ll iterate through an array of size values. Changes to the @State property sizeIndex updates the capsule to a new size in the array.' 提示: '' - 翻译: '' + 翻译: '为了改变胶囊的大小,你将遍历一个 size 值的数组。对 @State 属性 sizeIndex 的更改会将胶囊更新为数组中的新大小。' - 内容: 'Experiment' 提示: '' - 翻译: '' + 翻译: '实验' - 内容: 'Try adding a few sizes of your own. Can you make a really big or really tiny capsule?' 提示: '' - 翻译: '' + 翻译: '尝试添加一些自己的尺寸。你能做一个非常大或非常小的胶囊吗?' - 内容: 'The capsule shape uses the sizes value in the frame modifier to set its width and height based on the sizeIndex. If the index changes, this view automatically updates to reflect the new size it references in the array.' 提示: '' - 翻译: '' + 翻译: '胶囊形状使用 frame 修饰符中的 sizes 值来根据 sizeIndex 设置其宽度和高度。如果索引发生变化,这个视图会自动更新以反映出它在数组中引用的新大小。' - 内容: 'What happens if you set the width’s index to 1 with sizes[1].width? What happens each time you touch and hold on the capsule? Try it before moving on.' 提示: '' - 翻译: '' + 翻译: '如果你使用 sizes[1].width 将宽度的索引设置为 1,会发生什么?每次你触摸并保持胶囊时会发生什么?在继续之前试一试。' - 内容: 'Here you define your custom gesture using a LongPressGesture.' 提示: '' - 翻译: '' + 翻译: '这里你使用 LongPressGesture 定义了你的自定义手势。' - 内容: 'When the long press gesture ends, iterate to the next index in the array. The value increments by 1 until it reaches the last index (sizes.count) before resetting back to 0.' 提示: '' - 翻译: '' + 翻译: '当长按手势结束时,sizeIndex 会迭代到数组中的下一个索引。该值增加 1,直到它达到最后一个索引(sizes.count),然后重置为 0。' - 内容: 'The last step is to apply the long press gesture to the capsule shape using the .gesture modifier. The app calls event handlers from longPressGesture when you touch and hold the capsule.' 提示: '' - 翻译: '' + 翻译: '最后一步是使用 .gesture 修饰符将长按手势应用到胶囊形状上。当你触摸并保持胶囊时,应用程序会通过 longPressGesture 调用事件处理器。' - 内容: 'Drag' 提示: '' - 翻译: '' + 翻译: '拖动' - 内容: 'Learn how to use a drag gesture to move a circle around the screen.' 提示: '' - 翻译: '' + 翻译: '学习如何使用拖动手势在屏幕上移动一个圆。' - 内容: 'In DragView you’ll use a drag gesture to move a circle shape around the view.' 提示: '' - 翻译: '' + 翻译: '在 DragView 中,你将使用拖动手势在视图中移动一个圆形。' - 内容: 'To keep track of the circle’s position, the @State variable offset stores a CGSize value. This doesn’t refer to the circle’s size, but is instead used as a distance vector to represent its offset from its starting position in the view.' 提示: '' - 翻译: '' + 翻译: '为了跟踪圆的位置,@State 变量 offset 存储了一个 CGSize 值。这并不是指圆的大小,而是用作距离向量来表示它在视图中的起始位置的偏移量。' - 内容: 'Here you pass in offset as the value for the circle view’s .offset modifier. Any change to this value causes SwiftUI to update the position of the circle relative to its original location in the view. As your gesture updates offset, the circle moves around the view.' 提示: '' - 翻译: '' + 翻译: '这里你将 offset 作为圆视图的 .offset 修饰符的值传入。对该值的任何更改都会导致 SwiftUI 更新圆相对于视图中原始位置的位置。当你的手势更新 offset 时,圆会在视图中移动。' - 内容: 'Here you define a custom gesture using a DragGesture.' 提示: '' - 翻译: '' + 翻译: '这里你使用 DragGesture 定义了一个自定义手势。' - 内容: 'The system calls the .onChanged event handler any time the position of your drag changes. Each time the handler is called, it assigns a new value to offset using the translation property of the drag value.' 提示: '' - 翻译: '' + 翻译: '系统会在拖动位置发生变化时调用 .onChanged 事件处理器。每次调用处理器时,它都会使用拖动值的 translation 属性为 offset 赋一个新值。' - 内容: 'Try modifying this formula to see what happens to your circle when you drag it. What happens when you remove the -50 (the radius of the circle) from the width and height? What happens if you remove the start location of the width and height?' 提示: '' - 翻译: '' + 翻译: '尝试修改这个公式,看看当你拖动它时你的圆会发生什么。当你从宽度和高度中删除 -50(圆的半径)时会发生什么?如果你删除宽度和高度的起始位置会发生什么?' - 内容: 'To apply the drag gesture to the circle, pass in the dragGesture to the .gesture modifier of the circle.' 提示: '' - 翻译: '' + 翻译: '将拖动手势应用到圆上,将 dragGesture 传入到圆的 .gesture 修饰符中。' - 内容: 'Rotate' 提示: '' - 翻译: '' + 翻译: '旋转' - 内容: 'Experiment rotating a square using two fingers.' 提示: '' - 翻译: '' + 翻译: '尝试使用两根手指旋转一个正方形。' - 内容: 'In RotateView you’ll use a two-finger rotation gesture to rotate a square shape.' 提示: '' - 翻译: '' + 翻译: '在 RotateView 中,你将使用双指旋转手势来旋转一个正方形。' - 内容: 'To set up the rotation gesture, you need a starting angle, rotation. This state property enables you to track the change of rotation, and redraws the view every time it changes.' 提示: '' - 翻译: '' + 翻译: '为了设置旋转手势,你需要一个起始角度 rotation。这个状态属性使你能够跟踪旋转的变化,并在每次变化时重新绘制视图。' - 内容: 'You pass in rotation as the value for the .rotationEffect modifier, enabling the view to update the rotation angle as the value changes.' 提示: '' - 翻译: '' + 翻译: '你将 rotation 作为 .rotationEffect 修饰符的值传入,使视图能够在值变化时更新旋转角度。' - 内容: 'Here you define a custom gesture using a RotationGesture.' 提示: '' - 翻译: '' + 翻译: '这里你使用 RotationGesture 定义了一个自定义手势。' - 内容: 'While you rotate the square, the rotation property constantly updates the value of the @State property, rotation. SwiftUI then detects those changes and tells the square to redraw itself.' 提示: '' - 翻译: '' + 翻译: '当你旋转正方形时,rotation 属性不断更新 @State 属性 rotation 的值。SwiftUI 会检测到这些变化,并告诉正方形重新绘制自己。' - 内容: 'To capture the gesture’s final value, use the onEnded event handler. This updates rotation with the last value from the gesture and draws the square view to perfectly match the angle of your last movement.' 提示: '' - 翻译: '' + 翻译: '为了捕获手势的最终值,使用 onEnded 事件处理器。这会使用手势的最后一个值更新 rotation,并绘制正方形视图以完美匹配你最后一次移动的角度。' - 内容: 'Note' 提示: '' - 翻译: '' + 翻译: '注意' - 内容: 'You could remove this whole section of code, and you might not notice any difference when you rotate the square. However, if you record the exact angles, you might notice a small difference between the final angle of your finger movements and the final angle of the square after it stops rotating.' 提示: '' - 翻译: '' + 翻译: '你可以删除这整个代码部分,当你旋转正方形时你可能不会注意到任何不同。然而,如果你记录下确切的角度,你可能会注意到你的手指移动的最终角度和正方形停止旋转后的最终角度之间的微小差异。' - 内容: 'Step 7' 提示: '' 翻译: '' - 内容: 'The last step required to make this square rotate is to add the .gesture modifier to the square, passing in rotationGesture so it responds to your touch.' 提示: '' - 翻译: '' + 翻译: '最后一步是让这个正方形旋转,将 .gesture 修饰符添加到正方形中,传入 rotationGesture 使它响应你的触摸。' - 内容: 'The rotation gesture is only available on Multi-Touch devices (Magic Mouse, Magic Trackpad, MacBook, or iOS devices), and may not be available in some macOS configurations. For more details, see Using Multi-Touch gestures on your Mac.' 提示: '' - 翻译: '' + 翻译: '旋转手势仅适用于多点触摸设备(Magic Mouse、Magic Trackpad、MacBook 或 iOS 设备),并且可能在某些 macOS 配置中不可用。有关更多详细信息,请参阅在 Mac 上使用多点触摸手势。' - 内容: 'Line Drawing' 提示: '' - 翻译: '' + 翻译: '线段绘制' - 内容: 'Explore how to draw lines onscreen using a drag gesture.' 提示: '' - 翻译: '' + 翻译: '探索如何使用拖动手势在屏幕上绘制线条。' - 内容: 'In SingleLine, you’ll use a drag gesture to draw a line in the view. To do this, you’ll create a Path and redraw it every time you initiate a drag event.' 提示: '' - 翻译: '' + 翻译: '在 SingleLine 中,你将使用拖动手势在视图中绘制一条线。为此,你将创建一个 Path,并在每次启动拖动事件时重新绘制它。' - 内容: 'This drag gesture needs two state properties: one to track the start of the line, and one to track the end of the line.' 提示: '' - 翻译: '' + 翻译: '这个拖动手势需要两个状态属性:一个用来跟踪线的起点,一个用来跟踪线的终点。' - 内容: 'To draw a line, you’ll use a Path, which creates an outline of a shape. First, you’ll move the path to the lineStart value and then you’ll add a line to the lineEnd value. Because each of these values are @State properties, any changes to their data causes SwiftUI to redraw the path and update the view. As a result, you can see the line updating as you drag around the view.' 提示: '' - 翻译: '' + 翻译: '为了绘制一条线,你将使用 Path,它创建了一个形状的轮廓。首先,你将把路径移动到 lineStart 的值,然后你将在 lineEnd 的值上添加一条线。因为这些值都是 @State 属性,所以对它们的数据的任何更改都会导致 SwiftUI 重新绘制路径并更新视图。因此,你可以看到当你在视图周围拖动时,线条在更新。' - 内容: 'This drag gesture example uses a DragGesture, just like the other drag gesture example. However, here you need two event handlers: one that’s called as the drag value changes in .onChanged, and the other that’s called when the drag gesture ends in .onEnded.' 提示: '' - 翻译: '' + 翻译: '这个拖动手势示例使用 DragGesture,就像其他拖动手势示例一样。然而,在这里你需要两个事件处理器:一个在 .onChanged 中调用,当拖动值改变时,另一个在 .onEnded 中调用,当拖动手势结束时。' - 内容: 'When your device detects a drag gesture, lineStart uses the initial location of the drag, and this value remains constant. However, lineEnd updates with a new location for each .onChanged event sent. This allows the line to redraw, making it look like you’re dragging the end of the line wherever you want it to go.' 提示: '' - 翻译: '' + 翻译: '当你的设备检测到拖动手势时,lineStart 使用拖动的初始位置,这个值保持不变。然而,lineEnd 会使用每个 .onChanged 事件发送的新位置进行更新。这将会让线条重新绘制,使它看起来像你在拖动线条的末端。' - 内容: 'The second event handler, .onEnded, captures the last location of your drag and updates the lineEnd property, ensuring your line ends where your touch left the view. After the .onEnded handler recognizes that you’ve stopped drawing, the line stays in place until you start a new drag gesture.' 提示: '' - 翻译: '' + 翻译: '第二个事件处理器 .onEnded 会捕获你拖动的最后位置,并更新 lineEnd 属性,确保你的线条在你的触摸离开视图的地方结束。在 .onEnded 处理程序识别到你已经停止绘制之后,线条会保持在原地,直到你开始一个新的拖动手势。' - 内容: 'To assign the gesture, pass in lineDrawingGesture to the .gesture modifier of your Path.' 提示: '' - 翻译: '' + 翻译: '为了让手势生效,将 lineDrawingGesture 传递给 Path 的 .gesture 修饰符。' - 内容: 'Animating Shapes' 提示: '' - 翻译: '' + 翻译: '动画形状' - 内容: 'Learn how to use shapes and simple animations in SwiftUI.' 提示: '' - 翻译: '' + 翻译: '学习如何在 SwiftUI 中使用形状和简单的动画。' From 0e4e5e1bb37949c99886e602b7e8a9a08407b5a4 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 21:44:06 +0800 Subject: [PATCH 8/9] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=20animate=20shap?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project/sample-apps/animatingshapes.yml | 148 ++++++++++++------------ 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/project/sample-apps/animatingshapes.yml b/project/sample-apps/animatingshapes.yml index be4f4ab..f8004d7 100644 --- a/project/sample-apps/animatingshapes.yml +++ b/project/sample-apps/animatingshapes.yml @@ -1,273 +1,273 @@ - 内容: 'Animating Shapes' 提示: '' - 翻译: '' + 翻译: '动画形状' - 内容: 'Learn how to use shapes and simple animations in SwiftUI.' 提示: '' - 翻译: '' + 翻译: '学习如何在 SwiftUI 中使用形状和简单动画。' - 内容: 'First up, you’ll learn to use the SwiftUI Shape protocol to create and modify shape views.' 提示: '' - 翻译: '' + 翻译: '首先,你将学习使用 SwiftUI Shape 协议来创建和修改形状视图。' - 内容: 'You’ll learn the basics of animating views and how to create animations – some easy, some more complex!' 提示: '' - 翻译: '' + 翻译: '你将学习动画视图的基础知识以及如何创建动画 - 有些简单,有些更复杂!' - 内容: 'Heart Pulse' 提示: '' - 翻译: '' + 翻译: '心脏脉冲' - 内容: 'Discover how to make a heart pulse in this basic animation.' 提示: '' - 翻译: '' + 翻译: '探索如何在这个基本动画中使心脏跳动。' - 内容: 'Step 1' 提示: '' 翻译: '' - 内容: 'In this walkthrough, you will learn how to create a custom heart shape as well as how to make it pulse. From there, you’ll learn how to scale the pulsing heart up or down.' 提示: '' - 翻译: '' + 翻译: '在这个演练中,你将学习如何创建一个自定义的心形,以及如何让它跳动。从那里开始,你将学习如何将跳动的心脏放大或缩小。' - 内容: 'Step 2' 提示: '' 翻译: '' - 内容: 'To create a heart shape, define a structure that adopts the Shape protocol by implementing the required path(in:) method.' 提示: '' - 翻译: '' + 翻译: '为了创建一个心形,这里你通过实现 required path(in:) 方法,定义一个采用 Shape 协议的结构。' - 内容: 'Step 3' 提示: '' 翻译: '' - 内容: 'path.move starts the path at the point of the heart.' 提示: '' - 翻译: '' + 翻译: 'path.move 从心脏的点开始路径。' - 内容: 'Step 4' 提示: '' 翻译: '' - 内容: 'path.addCurve creates a curved line from where your point is to a specified end point. This is what draws the curved sides of the heart shape.' 提示: '' - 翻译: '' + 翻译: 'path.addCurve 会从你指定的起点到终点创建一条曲线。这就是绘制心形的曲线边的方法。' - 内容: 'Step 5' 提示: '' 翻译: '' - 内容: 'path.addArc adds the arcs at the top of the heart shape. By specifying the start and end angles, the path knows where to draw the arc. The arc is drawn off of specific points in the unit circle that you specify for the start and end angles.' 提示: '' - 翻译: '' + 翻译: 'path.addArc 会在心形的顶部添加圆弧。通过指定起始角度和结束角度,Path 实例知道在哪里绘制圆弧。圆弧是从你为起始角度和结束角度指定的单位圆的特定点绘制的。' - 内容: 'Step 6' 提示: '' 翻译: '' - 内容: 'To make the heart pulse, you’ll tap the play button. When the heart pulses, it scales up and then back down, repeating the animation indefinitely. Your heartPulse state property determines the scale of the heart in this animation.' 提示: '' - 翻译: '' + 翻译: '为了让心脏跳动,你将点击播放按钮。当心脏跳动时,它会放大然后缩小,无限期地重复动画。在这个动画中,你的 heartPulse 状态属性决定了心脏的比例。' - 内容: 'Step 7' 提示: '' 翻译: '' - 内容: 'When you tap play, the heartPulse value increases. Setting autoreverses to true allows the animation to first play forward, as the heart scales up, and then backward as it scales back down again.' 提示: '' - 翻译: '' + 翻译: '当你点击播放时,heartPulse 值会增加。将 autoreverses 设置为 true 允许动画首先正向播放,这会使心脏放大,然后反向播放,这会使它缩小。' - 内容: 'Step 8' 提示: '' 翻译: '' - 内容: 'By changing the value of heartPulse inside of a withAnimation closure, you animate any changes to its value with the animation you pass in, resulting in the pulsing effect. 💗' 提示: '' - 翻译: '' + 翻译: '通过在 withAnimation 闭包中更改 heartPulse 的值,你可以使用传入的动画来动画化其值的任何更改,从而产生跳动的效果。💗' - 内容: 'Spinning Animation' 提示: '' - 翻译: '' + 翻译: '旋转动画' - 内容: 'Discover how to create a spinning effect.' 提示: '' - 翻译: '' + 翻译: '探索如何创建旋转效果。' - 内容: 'Next, you’ll learn to create a spinning animation when you tap a button. Time to get dizzy!' 提示: '' - 翻译: '' + 翻译: '接下来,你将学习如何在点击按钮时创建旋转动画。是时候让你头晕了!' - 内容: 'There is no preset animation that actually causes a shape to spin, but you can create the illusion of spinning by changing the width of the shape. To do this, you’ll use a width state property.' 提示: '' - 翻译: '' + 翻译: '这里没有预设的动画可以让形状旋转,但是你可以通过改变形状的宽度来制造旋转的幻觉。为此,你将使用一个 width 状态属性。' - 内容: 'When you tap the button, the ellipse animates to change its width from 200 to 0. Notice that the Animation used is .easeInOut.repeatForever(autoreverses: true).speed(2). This chains together three animations to create a specific effect. Try to predict how each part of the animation affects the overall effect.' 提示: '' - 翻译: '' + 翻译: '当你点击按钮时,椭圆动画将其宽度从 200 改变为 0。注意,使用的动画是 .easeInOut.repeatForever(autoreverses: true).speed(2)。这将三个动画链接在一起,以创建一个特定的效果。你可以试着预测动画的每个部分如何影响整体效果。' - 内容: 'Here’s the sequence: .easeInOut first creates an animation that eases in and eases out. Then .repeatForever(autoreverses: true) takes the .easeInOut animation and puts it in a loop that runs forever. Because autoreverses is true, the animation first runs forward, then in reverse before starting over. And finally, .speed(2) determines how quickly the animation runs. With an argument of 2, it runs at 200 percent of its default speed.' 提示: '' - 翻译: '' + 翻译: '动画的执行顺序如下:.easeInOut 首先创建一个缓入缓出的动画。然后 .repeatForever(autoreverses: true) 将 .easeInOut 动画放入一个永远运行的循环中。因为 autoreverses 是 true,所以动画首先正向运行,然后反向运行,然后再重新开始。最后,.speed(2) 确定动画运行的速度。使用 2 作为参数,它以其默认速度的 200% 运行。' - 内容: 'This animation results in a spinning effect as the circle’s width changes first from 200 to 0, and then from 0 to 200, repeating the entire animation on a recurring loop.' 提示: '' - 翻译: '' + 翻译: '这个动画会产生一个旋转的效果,因为圆的宽度首先从 200 变为 0,然后从 0 变为 200,在一个循环中重复整个动画。' - 内容: 'Exploding Animation' 提示: '' - 翻译: '' + 翻译: '爆炸动画' - 内容: 'Learn how to create an explosion effect.' 提示: '' - 翻译: '' + 翻译: '学习如何创建爆炸效果。' - 内容: 'To create an exploding animation, you’ll replace a rectangle with many small rectangular pieces that animate outward.' 提示: '' - 翻译: '' + 翻译: '要创建一个爆炸动画,你将用许多小的矩形块替换一个矩形,这些矩形块会以动画的形式向外移动。' - 内容: 'The isExploded state property tracks whether the exploding animation is currently running. You’ll use this value to start all of the animations when you tap the button.' 提示: '' - 翻译: '' + 翻译: '这个 isExploded 状态属性会跟踪爆炸动画是否正在运行。你将使用这个值来在点击按钮时启动所有的动画。' - 内容: 'In the large Rectangle view, the opacity animates from 1 to 0 when isExploded is set to true; this makes the large rectangle disappear.' 提示: '' - 翻译: '' + 翻译: '在这个大的 Rectangle 视图中,当 isExploded 设置为 true 时,不透明度从 1 以动画的形式变化为 0;这使得这个大矩形消失。' - 内容: 'When the large rectangle disappears, you want many small rectangles to explode outward. To create this effect, you’ll first generate a large number of smaller rectangles using a ForEach. These rectangles are initially hidden behind the large rectangle in a ZStack. When the large rectangle disappears, you’ll see the smaller rectangles.' 提示: '' - 翻译: '' + 翻译: '当这个大矩形消失时,你希望出现许多小矩形向外爆炸。为了创建这个效果,你首先要使用 ForEach 生成大量的小矩形。这些矩形最初被隐藏在一个 ZStack 中的大矩形后面。当大矩形消失时,你会看到这些小矩形。' - 内容: 'Experiment' 提示: '' - 翻译: '' + 翻译: '实验' - 内容: 'Try changing the number of small rectangles to see how that affects the animation.' 提示: '' - 翻译: '' + 翻译: '尝试改变小矩形的数量,看看这对动画有什么影响。' - 内容: 'For each of these small rectangles, you’ll use a conditional modifier to animate their offsets to random positions in the view. This makes it look like they’re little shards of the larger rectangle that propel out in different directions.' 提示: '' - 翻译: '' + 翻译: '对于这些小矩形,你将使用一个条件修饰符来将它们的偏移量动画到视图中的随机位置。这使得它们看起来像是大矩形的小碎片,朝不同的方向喷射出去。' - 内容: 'Add a twist! Try changing the speed of the ease-in -out animation for the small rectangles and see what happens.' 提示: '' - 翻译: '' + 翻译: '加点变化!尝试改变小矩形的缓入缓出动画的速度,看看会发生什么。' - 内容: 'As those little rectangles explode out, you’ll fade their opacity from 1 to 0 so they eventually disappear. And that’s your explosion animation. Now, you may be thinking, “This isn’t a real explosion, it’s an illusion.”, and you’re absolutely right. All animations are illusions, and you’re the magician who creates them. 🪄' 提示: '' - 翻译: '' + 翻译: '当这些小矩形爆炸时,你会将它们的不透明度从 1 渐变为 0,这样它们最终会消失。这就是你的爆炸动画。现在,你可能会想,“这不是一个真正的爆炸,这只是一个幻觉。”,你是绝对正确的。所有的动画都是幻觉,而你就是创造它们的魔术师。🪄' - 内容: 'Use scaling and animation delays to create a wave effect.' 提示: '' - 翻译: '' + 翻译: '使用缩放和动画延迟来创建波浪效果。' - 内容: 'Now that you’ve dabbled with some basic animations, take a look at how you can combine them to create a more advanced interactive effect. You’ll learn how to animate a grid of circles to form a fabulous wave effect when you tap them. In the preview, try tapping on different circles in the grid. What do you notice?' 提示: '' - 翻译: '' + 翻译: '现在你已经尝试了一些基本的动画,看看你如何将它们结合起来创建一个更高级的交互效果。你将学习如何对一个圆圈网格进行动画处理,当你点击它们时,它们会形成一个神奇的波浪效果。在预览中,尝试点击网格中的不同圆圈。你注意到了什么?' - 内容: 'You’ll need a few state properties to keep track of how the circles change when you tap them. The gridColumns property defines the columns for the grid, and colors provides the color options for the rainbow effect.' 提示: '' - 翻译: '' + 翻译: '你将需要一些状态属性来跟踪圆圈在你点击它们时的变化。gridColumns 属性定义了网格的列,colors 为彩虹效果提供了颜色选项。' - 内容: 'Try changing the number of columns, by changing the value for count in gridColumns. What happens if you change the colors in the colors array?' 提示: '' - 翻译: '' + 翻译: '尝试通过改变 gridColumns 中 count 的值来改变列数。如果你改变 colors 数组中的颜色会发生什么?' - 内容: 'The numCircles constant defines the number of circles in your grid. Your LazyVGrid uses gridColumns and numCircles to generate the initial grid of circles.' 提示: '' - 翻译: '' + 翻译: 'numCircle 常量定义了网格中圆圈的数量。你的 LazyVGrid 使用 gridColumns 和 numCircles 来生成圆圈的初始网格。' - 内容: 'Try changing the value of numCircles and see how your grid changes.' 提示: '' - 翻译: '' + 翻译: '尝试改变 numCircles 的值,看看你的网格如何变化。' - 内容: 'The springAnimation constant defines the animation to use later in the animation modifier.' 提示: '' - 翻译: '' + 翻译: 'springAnimation 常量定义了稍后在动画修饰符中使用的动画。' - 内容: 'Try changing some of these values and tap the grid to see how they affect the animation.' 提示: '' - 翻译: '' + 翻译: '尝试改变其中一些值,然后点击网格,看看它们如何影响动画。' - 内容: 'Your springAnimation is used to animate changes to the scale of the circles in the grid. However, to create a rolling wave effect you want to animate the circles in your grids at different times. Add delay(_:) to springAnimation to specify the duration of the animation delay for each individual circle. To calculate the delay, divide the circle’s index by the number of columns, taking the truncating remainder as a value between 1 and 10 (the number of columns). This creates a per-column animation effect.' 提示: '' - 翻译: '' + 翻译: '你的 springAnimation 用于对网格中圆圈的缩放进行动画处理。然而,为了创建一个滚动的波浪效果,你希望以不同的时间对网格中的圆圈进行动画处理。将 delay(_:) 添加到 springAnimation 中,以指定每个单独圆圈的动画延迟持续时间。为了计算延迟,将圆圈的索引除以列数,将截断的余数作为 1 到 10 之间的值(列数)。这样就创建了一个每列动画效果。' - 内容: 'The .animation modifier determines how the circle animates, but the value for scaleFactor and any changes made to scaleFactor are what causes the increase in scale.' 提示: '' - 翻译: '' + 翻译: '.animation 修饰符决定了圆圈的动画方式,但是 scaleFactor 的值和对 scaleFactor 的任何更改才是导致缩放增加的原因。' - 内容: 'The tapGesture modifier allows you to change the scaleFactor by tapping a circle in the grid. When you tap a circle, the value of scaleFactor is set based on that circle’s index. The further the circle’s position is in the grid, the larger the scaleFactor will be.' 提示: '' - 翻译: '' + 翻译: 'tapGesture 修饰符允许你通过点击网格中的一个圆圈来改变 scaleFactor。当你点击一个圆圈时,scaleFactor 的值是基于该圆圈的索引设置的。圆圈在网格中的位置越远,scaleFactor 就越大。' - 内容: 'Because the index of circles starts at 0, you need to set the scaleFactor using index+1 so you never have to set the scaleFactor to an undefined number.' 提示: '' - 翻译: '' + 翻译: '因为圆圈的索引从 0 开始,所以你需要使用 index+1 来设置 scaleFactor,这样你就永远不需要将 scaleFactor 设置为一个未定义的数字。' - 内容: 'Step 9' 提示: '' 翻译: '' - 内容: 'There you have it…a beautiful rolling rainbow!' 提示: '' - 翻译: '' + 翻译: '就是这样...你已经拥有了美丽的的滚动彩虹' - 内容: 'Try tinkering with this animation until it’s exactly as you like it. Good luck!' 提示: '' - 翻译: '' + 翻译: '尝试调整这个动画,直到它完全符合你的喜好。祝你好运!' - 内容: 'Use a drag gesture to move a grid of dots.' 提示: '' - 翻译: '' + 翻译: '使用拖动手势来移动一个网格的点。' - 内容: 'Draggin’ Drop Dots is very similar to Rollin’ Rainbow, but with some differences. Instead of changing the scale of the circles when you tap them, the circle’s offset changes based on a drag gesture applied to the entire grid. Time to dive into the code.' 提示: '' - 翻译: '' + 翻译: 'Draggin’ Drop Dots 与 Rollin’ Rainbow 非常相似,但也有一些不同之处。当你点击圆圈时,圆圈的偏移量会根据应用于整个网格的拖动手势而改变,而不是改变圆圈的缩放。是时候深入代码了。' - 内容: 'This is a much larger grid than Rollin’ Rainbow – there are a lot more circles and columns. See what happens when you change the number of dots in the grid. Do you need more circles in this animation?' 提示: '' - 翻译: '' + 翻译: '这是一个比 Rollin’ Rainbow 大得多的网格——有更多的圆圈和列。看看当你改变网格中的点数时会发生什么。你需要在这个动画中有更多的圆圈吗?' - 内容: 'Add a drag gesture instead of a tap gesture so the grid moves when you drag it. You can use the translation value in the drag gesture closure to set the offset of each circle, resulting in the entire grid moving to the new drag.translation value.' 提示: '' - 翻译: '' + 翻译: '添加一个拖动手势,而不是一个点击手势,这样当你拖动它时,网格就会移动。你可以在拖动手势闭包中使用 translation 值来设置每个圆圈的偏移量,从而导致整个网格移动到新的 drag.translation 值。' - 内容: 'When the offset changes, you’ll animate the circles to their new positions. Instead of moving all of the dots at the same time, you can use delay on the animation so that each circle moves individually. If you set the delay based on each circle’s index, the circles will have a slightly different delay. This results in the entire grid animating one circle after the other. Because this animation would otherwise be very slow, you can divide the value for delay by the animationSpeed value to speed it up.' 提示: '' - 翻译: '' + 翻译: '当手势的偏移量发生变化时,你将对圆圈进行动画处理,使它们处于新的位置。你可以使用动画上的延迟,而不是同时移动所有的点,这样每个圆圈就可以单独移动。如果你根据每个圆圈的索引设置延迟,那么圆圈的延迟就会略有不同。这导致整个网格会在一个圆圈之后动画执行结束之后再执行另一个圆圈的动画。因为这个动画本来会非常慢,所以你可以将延迟的值除以 animationSpeed 的值来加快速度。' - 内容: 'Try changing the animationSpeed to something very low, like 20. How does the animation change?' 提示: '' - 翻译: '' + 翻译: '尝试将 animationSpeed 更改为非常低的值,比如 20。动画会如何变化?' - 内容: 'Dancing Dots' 提示: '' - 翻译: '' + 翻译: '跳舞的点' - 内容: 'Make the circles boogie!' 提示: '' - 翻译: '' + 翻译: '让圆圈跳舞!' - 内容: 'Animate more complex model data in cool and interesting ways using observable objects.' 提示: '' - 翻译: '' + 翻译: '让更多复杂的模型数据以有趣的方式使用 observable 对象进行动画处理。' - 内容: 'What if the changes you want to animate aren’t coming from user actions? SwiftUI has a way of animating published values in observable objects. Create an observable object BigDot that publishes an offset, color, scale, and an array of small dot observable objects. You’ll use this object to model the view animations you want in your view.' 提示: '' - 翻译: '' + 翻译: '如果你想要动画处理的变化不是来自用户的操作怎么办?SwiftUI 有一种方法可以对 observable 对象中发布的值进行动画处理。创建一个 observable 对象 BigDot,它发布一个偏移量、颜色、比例和一个小点 observable 对象的数组。你将使用这个对象来模拟你在视图中想要的视图动画。' - 内容: 'Add a SmallDot observable object that publishes a color and an offset.' 提示: '' - 翻译: '' + 翻译: '添加一个 SmallDot observable 对象,它将发布一个颜色和一个偏移量。' - 内容: 'When you create a bigDot, you also need to create an array of small dots that are linked to the big dot.' 提示: '' - 翻译: '' + 翻译: '当你创建一个 bigDot 时,你还需要创建一个与 bigDot 相关联的 smallDot 数组。' - 内容: 'Now, a grid of big dots needs to populate the grid with five small dots for every big dot. Because there are so many dots, you’ll use a DotTracker class when publishing an array of BigDots. This is the published value you’ll track to create your animations. What happens to the animation if you increase or decrease the number of smallDots in the array?' 提示: '' - 翻译: '' + 翻译: '现在,一个大点的网格需要为每个大点填充五个小点。因为有这么多的点,所以在发布一个 BigDots 数组时,你将使用一个 DotTracker 类。这是你将跟踪的发布值,以创建你的动画。如果你增加或减少数组中的 smallDots 数量,动画会发生什么?' - 内容: 'Your bigDots array has 100 BigDot instances that appear in the grid view.' 提示: '' - 翻译: '' + 翻译: '你的 bigDots 数组有 100 个 BigDot 实例,它们出现在网格视图中。' - 内容: 'You may notice that the BigDot class and DotTracker both include a randomizePositions() function that do almost the same thing. The function in BigDot creates random positions for each SmallDot in its smallDot array, while the function in DotTracker creates random positions for each BigDot. Together, these functions create the changes in the offset, color, and scale values reflected by animations in your grid view.' 提示: '' - 翻译: '' + 翻译: '你可能会注意到,BigDot 类和 DotTracker 都包含一个 randomizePositions() 函数,它们几乎做了相同的事情。BigDot 中的函数为其 smallDot 数组中的每个 SmallDot 创建随机位置,而 DotTracker 中的函数为每个 BigDot 创建随机位置。这些函数一起在网格视图中创建了偏移量、颜色和比例值的变化,这些变化反映在动画中。' - 内容: 'Try changing the value of the scale in the randomizePositions() function. What happens to the animation when you lower the scale value?' 提示: '' - 翻译: '' + 翻译: '尝试修改 randomizePositions() 函数中的 scale 值。当你降低 scale 值时,动画会发生什么?' - 内容: 'Add a resetPositions() function, so the dots reset to their original positions when you tap the reset button. This is very similar to the randomizePositions() function used to place circles in random locations around the view.' 提示: '' - 翻译: '' + 翻译: '添加一个 resetPositions() 函数,这样当你点击重置按钮时,点会重置到它们的原始位置。这与用于在视图周围随机位置放置圆圈的 randomizePositions() 函数非常相似。' - 内容: 'The randomizePositions() function calls bigDot.randomizePositions(). This puts every SmallDot in the smallDot array defined in the BigDot class into random positions.' 提示: '' - 翻译: '' + 翻译: 'randomizePositions() 函数会调用 bigDot.randomizePositions()。这将 BigDot 类中定义的 smallDot 数组中的每个 SmallDot 放置在随机位置。' - 内容: 'The DancingDotsView needs to define an instance of the DotTracker as a @StateObject so SwiftUI redraws its contents whenever any of the view’s dots change color or position.' 提示: '' - 翻译: '' + 翻译: 'DansingDotsView 需要将 DotTracker 的实例定义为 @StateObject,这样 SwiftUI 就会在视图的任何点的颜色或位置发生变化时重新绘制其内容。' - 内容: 'Step 10' 提示: '' 翻译: '' - 内容: 'Add in this ForEach loop to place each BigDot tracked by the tracker into the grid.' 提示: '' - 翻译: '' + 翻译: '将这个 ForEach 循环添加到 tracker 中,以将每个被 tracker 追踪的 BigDot 放置到网格中。' - 内容: 'Step 11' 提示: '' 翻译: '' - 内容: 'For each BigDot, you can create a circle view with its offset, color, and scale.' 提示: '' - 翻译: '' + 翻译: '对于每个 BigDot,你可以通过配置它的偏移量、颜色和比例来创建一个圆形视图。' - 内容: 'Step 12' 提示: '' 翻译: '' - 内容: 'Because every BigDot has five SmallDots, you can do the same thing for the small dots.' 提示: '' - 翻译: '' + 翻译: '因为每个 BigDot 都有五个 SmallDot,所以你可以对小点做同样的事情。' - 内容: 'Step 13' 提示: '' 翻译: '' - 内容: 'When you tap the play button, the circles animate and the randomizePositions() function is called. This causes the circles’ offsets to change, creating a dancing effect for the dots.' 提示: '' - 翻译: '' + 翻译: '当你点击播放按钮时,圆圈会执行动画,同时 randomizePositions() 函数会被调用。这会导致圆圈的偏移量发生变化,为点创建一个跳舞效果。' - 内容: 'Step 14' 提示: '' 翻译: '' - 内容: 'Add this isAnimating state property, which calls the resetPositions() method and resets the circle’s positions when you tap Reset.' 提示: '' - 翻译: '' + 翻译: '添加这个 isAnimating 状态属性,它会调用 resetPositions() 方法,并在你点击重置时重置圆圈的位置。' - 内容: 'Step 15' 提示: '' 翻译: '' - 内容: 'Because everything is animating, adding drawingGroup() helps to make the animation render smoothly.' 提示: '' - 翻译: '' + 翻译: '因为一切内容都在执行动画,所以添加 drawingGroup() 有助于使动画渲染平滑。' - 内容: 'Step 16' 提示: '' 翻译: '' - 内容: 'Now you know how to create more complex animations with shapes. Time to take what you’ve learned in this guide and use it to make some cool Swift apps!' 提示: '' - 翻译: '' + 翻译: '现在你知道如何使用形状创建更复杂的动画了。现在是时候将你在本指南中学到的知识用于制作一些很酷的 Swift 应用了!' - 内容: 'Previewing the Camera Output' 提示: '' - 翻译: '' + 翻译: '预览相机输出' - 内容: 'Preview the output from the camera.' 提示: '' - 翻译: '' + 翻译: '预览来自相机的输出。' - 内容: 'Rollin Rainbow' 提示: '' 翻译: '' From 8745be0c47317e278e1bb174454ce40c897659f1 Mon Sep 17 00:00:00 2001 From: onee Date: Tue, 18 Jul 2023 22:00:17 +0800 Subject: [PATCH 9/9] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project/swiftui/drawing-paths-and-shapes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/swiftui/drawing-paths-and-shapes.yml b/project/swiftui/drawing-paths-and-shapes.yml index ce9c5bd..49ef557 100644 --- a/project/swiftui/drawing-paths-and-shapes.yml +++ b/project/swiftui/drawing-paths-and-shapes.yml @@ -247,7 +247,7 @@ - 内容: Xcode recognizes the folder as containing all the size variations of an app icon and creates a corresponding item in the catalog. 提示: '' - 翻译: Xcode会识别该文件夹包含应用程序图标的所有不同尺寸,并且在目录中创建对应的项。 + 翻译: Xcode 会识别该文件夹包含应用程序图标的所有不同尺寸,并且在目录中创建对应的项。 - 内容: Step 9 提示: '' 翻译: 步骤 9