netflix_Netflix播放按钮剖析

netflix

We will develop a play pause button similar to the one the Netflix video player has.

我们将开发一个类似于Netflix视频播放器的播放暂停按钮。

Since Swift has replaced Objective-C as the default development language for iOS, the same will apply to SwiftUI and UIKit soon enough. Therefore we will be using SwiftUI to develop our button.

由于Swift已将Objective-C替换为iOS的默认开发语言,因此同样很快将适用于SwiftUI和UIKit。 因此,我们将使用SwiftUI开发按钮。

PlayButton.swift (PlayButton.swift)

Create a new Xcode project, using the iOS Single View Application template. Let’s call it PlayButtonDemo. In the next screen, make sure to select SwiftUI in the drop down menu titled User Interface.

使用iOS Single View Application模板创建一个新的Xcode项目。 我们称之为PlayButtonDemo 。 在下一个屏幕中,确保在标题为用户界面的下拉菜单中选择SwiftUI

Xcode’s showing options for your new project screen.

Create a new User Interface file, select the SwiftUI View option. Call it PlayButton.

创建一个新的用户界面文件,选择SwiftUI View选项。 称之为PlayButton

Xcode new file template with SwiftUI view selected.

In PlayButton.swift add an action property to the PlayButton struct, that takes a closure as its value. This will be the action the button performs when tapped.

PlayButton.swift中,action属性添加到PlayButton结构中,该属性将闭包作为其值。 这是轻按按钮时按钮执行的操作

var action: () -> Void

PlayButton_Preview will throw a "Missing Argument…" error. Fix it by supplying the action argument. We will set a simple action that prints Hello World!.

PlayButton_Preview将引发“ Missing Argument…”错误。 通过提供action参数对其进行修复。 我们将设置一个简单的动作来打印Hello World!

struct PlayButton_Previews: PreviewProvider {
static var previews: some View {
PlayButton {
print("Hello Button")
}
}
}

At the end of PlayButton, create a new Shape struct, called PlayPauseShape.

PlayButton的结尾,创建一个新的Shape结构,称为PlayPauseShape

The above will create a rectangular shape using the supplied rect parameter for dimensions.Back in PlayButton, change the default Text("Hello, World!") to PlayPauseShape(). Our Canvas will look like this.

上面将使用提供的rect参数创建尺寸的rectPlayButton ,将默认Text("Hello, World!")更改为PlayPauseShape() 。 我们的画布看起来像这样。

SwiftUI’s canvas showing the PlayPauseShape.

We clearly don’t intend to use a button that big. Let’s set a more appropriate size for our button.

我们显然不打算使用那么大的按钮。 让我们为按钮设置一个更合适的大小。

In PlayButton_Previews add a frame modifier to PlayButton.

PlayButton_Previews添加一个frame修饰符PlayButton

PlayButton {
print("Hello World!")
}
.frame(width: 128, height: 128)
SwiftUI Canvas with frame modifier set on PlayButton.

Before we start creating the shape, let’s complete PlayButton's construction, by making the button accessible and adding a tap gesture recognizer to it.

在开始创建形状之前,让按钮可访问并向其添加轻击手势识别器,以完成PlayButton的构建。

With regards to accessibility, when video is playing on device, the Pause button is what a user will see. Likewise, when video is paused, the user will see the Play button. Hence VoiceOver will report exactly what the button looks like.The .isButton accessibility trait, informs VoiceOver that it should report this UI element as a button. And finally, when the user double taps the element while it's in focus, VoiceOver will perform performTap(), the same function that our tap gesture recognizer calls.performTap() toggles the button's internal state, from pause to play and vice verca, and then calls the action that is passed in when setting up the button in its parent view.The .contentShape(Rectangle) modifier informs SwiftUI that the button's content has a rectangular shape, making the whole area tappable. Without this modifier, SwiftUI will mask the button's tappable hit area to the shape of our play/pause shape.With our type complete, let us turn our attention to the shape.

关于可访问性,当在设备上播放视频时,用户将看到“ 暂停”按钮。 同样,当视频暂停时,用户将看到“ 播放”按钮。 因此,VoiceOver将准确报告按钮的外观.isButton可访问性特征通知VoiceOver它应将此UI元素报告为按钮。 最后,当用户在焦点对准的位置上双击元素时,VoiceOver将执行performTap() ,这与我们的点击手势识别器调用的功能相同。 performTap()可以将按钮的内部状态从暂停状态切换为播放状态,然后从反之亦然,然后调用在其父视图中设置按钮时传递的动作。.contentShape .contentShape(Rectangle)修饰符通知SwiftUI该按钮的内容包含矩形,使整个区域都可以轻敲。 如果没有此修饰符, SwiftUI将把按钮的可点击击中区域遮盖为播放/暂停形状的形状。完成键入后,让我们将注意力转移到形状上。

PlayPauseShape (PlayPauseShape)

We want to split a triangle in half, we want each half to morph into a rectangle. The first challange would be to find the point D in the image below, the intersection of the triangle's top edge with the line running across its centre.

我们想将三角形​​分成两半,我们希望每个半都变形成矩形。 第一个挑战是在下图中找到点D ,即三角形的上边缘与穿过其中心的线的交点。

Triangle with a line in the middle.

It’s actually quite simple, all we need to do is, find the equation of the line using two points A (0, 0) and B (width, height * 0.5).First we find the slope M,M = (By - Ay)/(Bx - Ax) => M = (height * 0.5)/widthWe know that D = (width * 0.5, Dy)Substitue D with either A or B into the slope equation will get us the following:Dy = M(Dx - Ax) + Ay => Dy = (height * 0.5)/width * (width * 0.5)With regards to E, since the play shape is an equilateral triangle (the angles inside the triangle are all the same)Ey = height - Dy.

这其实很简单,我们需要做的是,找到使用两个点A(该直线的方程00 )和B( widthheight * 0.5 )。首先,我们发现斜率M,M =(B Y形 - Y)/(B X - X)=> M =( height * 0.5 )/ width我们知道,d =( width * 0.5 ,d y)的与AB成坡方程式Substitue d将得到我们D y = M ( D x - A x )+ A y => D y =( height * 0.5 )/ width *( width * 0.5 )关于E ,由于游戏形状是等边三角形 (角度三角形内部都相同) E y = height -D y

We will use a Path to draw the two halves, each half will be a subpath of the main path, and now that we have solved for all the unknowns (width and height are supplied to us by Shape's path(in:)) the first subpath will have the following points (A, D, E, C) and our second subpath will have (D, B, B, E). The duplicate B is not an error, we are animating from a triangle to a rectangular shape, it's better to just collpase the point onto it's self when it's a triangle.With regards to the pause shape, we provide each subpath with a rectangle that is offset from the center of the shape.

我们将使用Path绘制两半,每一半将成为主路径的子路径,现在我们已经解决了所有未知数(Shape的path(in:)提供了widthheight ),第一个子路径将具有以下点( ADEC ),而我们的第二个子路径将具有( DBBE )。 重复的B并不是错误,我们正在从三角形到矩形进行动画制作,最好是将点变成三角形时将其自身折叠起来。关于暂停形状,我们为每个子路径提供一个矩形从形状中心偏移。

Pause shape with a line in the middle.

In UIKit, animating between two paths is very easy using CABasicAnimation. In SwiftUI in not as straight forward. We need to provide a parameter to SwiftUI for interpolation. So if we wanted to animate from 0 to 1, SwiftUI will provide us with (0.0, 0.1, 0.2 ... 1.0). We inform SwiftUI of the parameter by implementing the animateableData property on types that conform to Animateable. Hence that parameter needs to be part of the path for the animation to take effect.

UIKit中 ,使用CABasicAnimation非常容易在两条路径之间进行动画处理。 在SwiftUI中并不是那么简单。 我们需要为SwiftUI提供参数进行插值。 因此,如果我们想从0到1进行动画处理,SwiftUI将为我们提供(0.0,0.1,0.2 ... 1.0)。 我们通过在符合Animateable类型上实现animateableData属性来告知SwiftUI参数。 因此,该参数必须是动画生效路径的一部分。

For a great write on SwiftUI animation, checkout out this post.

要获得有关SwiftUI动画的出色文章,请查看这篇文章

We’ll go through how to animate from the play shape’s A point to pause shape’s A point. We define the two points leftPlayTopLeftand leftPauseTopLeft. We find out how far the point has to move from pause's top left to play's top left. Mutliplying the result by the interpolation value and adding to leftPauseTopLeft will animate between to the two shapes.

我们将介绍如何从游戏形状的A点进行动画,以暂停形状的A点。 我们定义了两点leftPlayTopLeftleftPauseTopLeft 。 我们发现该点必须从暂停的左上角移动到游戏的左上角。 将结果与插值值leftPauseTopLeft并添加到leftPauseTopLeft将在这两个形状之间进行动画处理。

Back to PlayButton.swift, we will now define all 8 points as described above in a function called pathPoints. The value that is being interpolated her is the shift property.

返回PlayButton.swift ,我们现在将在上述名为pathPoints的函数中定义所有8个点。 她要插值的值是shift属性。

pathPoints(width:height) returns an array that's holding two arrays. The first array contains all the points for the left subpath, while the second array provides the points for the right subpath.We update path(in:) function to loop through the arrays and draw the lines.

pathPoints(width:height)返回一个包含两个数组的数组。 第一个数组包含左子路径的所有点,第二个数组提供右子路径的点。我们更新path(in:)函数以遍历数组并绘制线。

Click the Live Preview button in the canvas and tap away, you should get the button behaving as below.

单击画布中的“ 实时预览”按钮,然后轻按一下,您将获得如下所示的按钮。

Play button transitioning into pause button.

As always you can download the completed project from github.com.

与往常一样,您可以从github.com下载完成的项目。

Thank you for reading.

感谢您的阅读。

Image for post
UX Para Minas Pretas (UX For Black Women), a Brazilian organization focused on promoting equity of Black women in the tech industry through initiatives of action, empowerment, and knowledge sharing. Silence against systemic racism is not an option. Build the design community you believe in. UX Para Minas Pretas (UX For Black Women),这是一个巴西组织,致力于通过采取行动,赋权和知识共享的举措来促进科技行业中的黑人女性平等。 对系统性种族主义保持沉默是不可行的。 建立您相信的设计社区。

翻译自: https://uxdesign.cc/anatomy-of-the-netflix-play-button-d45cf0eb18c6

netflix

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值