mask在SwiftUI中是用于遮罩控件的,它能够依据咱们提供的形状或许图片来裁剪控件的可见区域。比方,咱们能够用圆形的mask来让一个图片控件变成圆形,或许用三角形mask一个按钮,只展示按钮的一个角等等

下面先看一个简略的例子,运用mask来显现图片。

SwiftUI:做一个好看的评分控件

Image("0")
            .resizable()
            .scaledToFit()
            .foregroundColor(.green)

咱们运用爱心来显现美人图片,运用 mask很容易抵达这个需求。

运用mask显现图形

办法界说如下,需求放回一个View

.mask(<#T##mask: () -> View##() -> View#>)

咱们只需求在mask的回来体中参加如下代码:

.mask {
  Image(systemName: "heart.fill")
                    .resizable()
                    .scaledToFit()
}

SwiftUI:做一个好看的评分控件

mask指定的形状是什么,终究的图形便是什么。所以终究的图形形状都有mask设定的图形决议


运用 mask创立突变评分控件

在很多场景中,都能够见到评分控件。它是由5个五角星组成,初始状态为灰色,当咱们点击五角星就会点亮色彩变成黄色。

首要,来创立五角星。

SwiftUI:做一个好看的评分控件

HStack {
            ForEach(1..<6) { index in
                Image(systemName: "star.fill")
                    .font(.largeTitle)
                    .foregroundColor(.orange)
            }
        }

运用上述代码即可创立五个五角星,可是它不具有动态功用。咱们来加上点击功用。

首要,咱们需求创立一个变量,来保存当时点击的是第几个星星。

@State var rating: Int = 1

其次,咱们需求运用不同前景色来区别已点击和未点击的五角星

.foregroundColor(rating >= index ? .orange : .gray)

终究,咱们给五角星参加点击事情。并且在点击事情中把当时的index值赋给rating。

.onTapGesture {
    rating = index
 }

下面是效果

可是,怎么给控件加突变色呢?咱们就要运用mask来完结这个任务。

首要,把创立五角星的代码提取成为一个变量starView。保持主body简略整洁,这个很重要。

var starView: some View {
        HStack {
            ForEach(1..<6) { index in
                Image(systemName: "star.fill")
                    .font(.largeTitle)
                    .foregroundColor(rating >= index ? .orange : .gray)
                    .onTapGesture {
                        rating = index
                    }
            }
        }
    }

其次,咱们给StartView增加一个overlay,将mask增加到overlay上。

ZStack {
                    starView
                        .overlay(
                            Rectangle()
                                .foregroundColor(.yellow)
                        )
                }

SwiftUI:做一个好看的评分控件

咱们能够看到,由于overlay的rectangle不知道宽度是多少,所以它会默许等于主视图的宽度。

咱们需求运用GometryReader来读取大小,然后操控overlay的宽度来展示底部五角星视图。由于overlay是在五角星视图上面的。所以咱们只有操控好上层视图的宽度,才能够看到基层视图

咱们还是把Overlay的内容提取成一个变量

var overlayView: some View {
            GeometryReader { geo in
                Rectangle()
                    .foregroundColor(.yellow)
                    .frame(width: CGFloat(rating) / 5 * geo.size.width)
            }
            .allowsHitTesting(false)
        }

frame(width: CGFloat(rating) / 5 * geo.size.width) 用于计算overlay的视图宽度,依据点击的index来决议视图显现的宽度是多少

SwiftUI:做一个好看的评分控件

当咱们点击五角星时,会发现视图的宽度和咱们预料的相同。可是还需求终究的一个mask。

在前面的例子中,咱们理解。mask作为一个用于遮罩控件。当你给定mask什么形状,终究的物体就会是给定的mask的样子。所以咱们把五角星的形状再设定给mask,就能够显现五角星了

ZStack {
      starView
        .overlay(overlayView.mask(starView))                
    }
var overlayView: some View {
            GeometryReader { geo in
                Rectangle()
                    .foregroundColor(.yellow)
                    .frame(width: CGFloat(rating) / 5 * geo.size.width)
            }
    }

此刻,就能够显现正常的五角星。

可是,此刻你会发现。能够把灰色五角星点亮,可是却无法再变成灰色。

那是由于,咱们把灰色变成黄色时,触发的是真实的五角星的点击事情。可是当咱们把五个五角星全部点亮,此刻就显现的是OverlayView的视图,OverlayView的视图阻挠了底部的点击事情。所以导致无法呼应事情,然后无法改动值,也就无法改动色彩了。那么咱们需求把OverlayView的点击事情禁用掉。

运用以下办法禁用视图点击事情

.allowsHitTesting(false)

allowsHitTesting

在 SwiftUI 中,allowsHitTesting特点主要用于操控视图是否能够接纳点击(hit test)事情。

  • 假如allowsHitTesting设置为true,则该视图能够接纳点击事情,默许为true。
  • 假如设置为false,则该视图将不再呼应任何点击事情,点击会透传给基层的视图。

需求注意的是它只影响点击事情,其他接触事情如长按、拖拽等不受影响。

好了,设置特点后,变得正常了。

加个动画

在点击事情中参加动画,让事情感觉动起来

.onTapGesture {
                            withAnimation(.easeInOut) {
                                rating = index
                            }
                        }

SwiftUI:做一个好看的评分控件

参加突变

有了以上基础,突变就很简略了。咱们只需求把overlayViewforegroundColor去掉。换成fill,然后在fill中运用一个突变来填充就OK了

var overlayView: some View {
            GeometryReader { geo in
                Rectangle()
    //                .foregroundColor(.yellow)
                    .fill(
                        LinearGradient(colors: [Color.blue, Color.green], startPoint: .leading, endPoint: .trailing)
                    )
                    .frame(width: CGFloat(rating) / 5 * geo.size.width)
            }
            .allowsHitTesting(false)
        }

我是用来清新的色彩来做为突变色,以上是终究效果。

大家有什么观点呢?欢迎留言评论。 公众号:RobotPBQ