8个SwiftUI的小技巧让隔壁同事两眼放光,直呼太卷了

8,998 阅读7分钟

在日常的SwiftUI开发过程中,常常会出现一些“小BUG”让我们措手不及、头顶发凉。这些问题可能是由于我们自己不熟悉SwiftUI语法导致的,也有是SwiftUI本身自带的缺陷,毕竟是一个新兴语言。

那么本章就介绍一些SwiftUI开发的小技巧,帮助我们避避那些让我们头秃的坑

1、如何在List列表视图去掉分割线LineSeparator?

SwiftUI中的List可以说是UIKit中TableView的进化版本,在UIKit中我们使用separatorColor修饰符将分割线的样式改为无。示例:

tableView.separatorColor = .clear

SwiftUI中使用的方法类似,SwiftUI中的List的底层使用的是UITableView,我们可以调用AppearanceAPI来实现去掉分割线样式。示例:

UITableView.appearance().separatorColor = .clear

1.png

但是,使用这种方式会导致App中所有的List,包含其他页面的的List也会自动去掉分割线,这是因为UITableViewList的底层,我们的修饰符是作用在UITableView上的。

往后我们要在其他页面,比如设置页面,要恢复分割线,我们就需要赋予分割线的样式。示例:

UITableView.appearance().separatorColor = .systemGray4

2.png

2、如何在List列表视图隐藏箭头?

UIKit中,我们使用accessoryType修饰符来禁用disclosure指示器,也就是右侧的箭头。示例:

cell.accessoryType = .none

SwiftUI中,非常遗憾的是,Apple没有提供专门的API来设置隐藏disclosure指示器,这会有点麻烦。

我们建立一个List列表来看看,当我们使用NavigationLink跳转到DetailView详情页时,系统就会自动展示右侧的箭头,示例:

3.png

那么我们试试自己来实现隐藏disclosure指示器。

struct ContentView: View {
    var body: some View {

        NavigationView {
            List {
                ForEach(1 ... 4, id: \.self) { index in
                    ZStack(alignment: .leading) {
                        NavigationLink(
                            destination: DetailView()) {
                        }
                        .opacity(0)

                        Text("第 \(index)页")
                    }
                }
            }.navigationTitle("列表")
        }
    }
}

4.png

上述代码中,我们使用ZStack层叠视图将整个NavigationLink的视图包裹起来,然后使用opacity修饰符把disclosure指示器隐藏。

看起来不错!

3、如何修改整个视图的背景颜色?

List列表中,由于我们使用SwiftUI自带的列表组件,它会默认给整个视图填充一个背景颜色以凸显列表,这时我们追求页面整体性时,需要给List视图加一个背景颜色。

UIKit中,我们可以直接给视图加背景颜色,示例:

view.backgroundColor = UIColor.colorF6F7FB()

首先,我们要去掉原有的List列表颜色,示例:

init() {

    UITableView.appearance().backgroundColor = .clear

}

然后在业务代码中,我们可以使用ZStack层叠视图和Color的方式设置List的背景颜色,示例:

Color(red: 132.0 / 255.0, green: 161.0 / 255.0, blue: 255.0 / 255.0).edgesIgnoringSafeArea(.all)

5.png

不错不错!

4、如何通过网络请求显示一张网络图片?

在常用的设置页面或者我的页面,会使用到用户头像等作为用户登录示例,除了使用第三方网络请求框架外,我们也可以使用SwiftUI自带的网络图片组件,示例:

AsyncImage(url: URL(string: imageURL))
    .aspectRatio(contentMode: .fit)
    .frame(minWidth: 120, maxWidth: 120, minHeight: 120, maxHeight: 120)
    .cornerRadius(8)

6.png

上述代码中,我们只需要定义一个图片的网络地址,就可以使用AsyncImage组件呈现一张图片出来,并且AsyncImageImage一样,可以使用修饰符修改大小的参数。

5、如何绘制带有边角的图形?

SwiftUI开发过程中,我们常常会看到一些带有部分圆角的形状,这又是如何实现的呢?

7.png

我们可以通过图片的方式展示,也可以自己根据形状绘制,下面我们尝试使用Shape形状来实现这个效果。示例:

struct CShape: Shape {
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(
            roundedRect: rect,
            byRoundingCorners: [.topRight, .bottomLeft],
            cornerRadii: CGSize(width: 55, height: 55)
        )
        return Path(path.cgPath)
    }
}

上述代码中,我们绘制了一个形状CShape结构体,在结构体中我们的定义了一个方法path,它返回一个Path路径。

我们使用贝塞尔曲线UIBezierPath进行绘制,在右上topRight和左下bottomLeft绘制曲率。

接下来我们在视图中使用,示例:

struct CShapeView: View {
    var body: some View {
       Rectangle()
            .fill(LinearGradient(gradient: Gradient(colors: [Color.blue, Color.green]), startPoint: .leading, endPoint: .trailing))
            .frame(width: 100, height: 100)
            .clipShape(CShape())
    }
}

8.png

上述代码中,我们绘制了一个矩形Rectangle,给它填充了一个蓝色过渡到绿色的渐变色,然后设置了大小为100*100

最后我们使用clipShape修饰符切割曲线,切割方式为上面设置好的CShape

这样,我们就完成了一个类似叶子效果的带边角的形状。

6、如何绘制虚线边框?

在新版的Xcode中,我们已经不能直接使用border修饰符给按钮加边框了,那我们该如何给按钮加边框线呢?

其实很简单,我们可以使用overlay修饰符在按钮上覆盖一层边框,示例:

Text("文如秋雨")
    .font(.title)
    .foregroundColor(.blue)
    .padding()
    .overlay(
        RoundedRectangle(cornerRadius: 30)
            .stroke(Color(.systemGray5), lineWidth: 2)
    )

9.png

上述代码中,我们使用overlay覆盖了一层圆角矩形RoundedRectangle,圆角度数为30,并且使用stroke修饰符给圆角赋予了一个灰色systemGray5,和2的线宽。

这是边框的实现方式,那么虚线边框我们使用的是Capsule容器。示例:

Text("文如秋雨")
    .font(.title)
    .foregroundColor(.blue)
    .padding()
    .overlay(
        Capsule(style: .continuous)
            .stroke(Color.blue, style: StrokeStyle(lineWidth: 2, dash: [10]))
    )

10.png

上述代码中,我们覆盖的是Capsule容器,然后将Capsule容器的样式指定为StrokeStyleStrokeStyle样式中线宽为2,线段间距为10

如此,我们便实现了绘制一个虚线边框

7、如何分享文本和图片?

在实际的开发应用中,我们常常会在App中使用分享操作,将某一段文字或者图片分享出去,这是如何实现的呢?

首先我们先实现分享的方法,示例:

struct ShareSheet: UIViewControllerRepresentable {
    var items: [Any]
    func makeUIViewController(context: Context) -> UIActivityViewController {
        let controller = UIActivityViewController(activityItems: items, applicationActivities: nil)
        return controller
    }
    func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
    }
}

上述代码中,我们创建了一个ShareSheet结构体,它遵循UIViewControllerRepresentable协议。

我们声明了一个items变量是随机类型,便于后续我们存储不同类型的内容。然后定义了一个方法makeUIViewController,调用系统的UIActivityViewController视图方法,分享声明好的items内容。

接下来,我们来完成视图部分,示例:

struct ShareLinkView: View {
    let items = ["https://juejin.cn/user/3897092103223517"]
    @State var showingSheet: Bool = false

    var body: some View {
        HStack {
            Image(systemName: "square.and.arrow.up")
            Text("分享")
        }
        .onTapGesture {
            showingSheet.toggle()
        }
        .sheet(isPresented: $showingSheet) {
            ShareSheet(items: items)
        }
    }
}

11.png

上述代码中,我们声明了一个常量,存储我们的网站地址,然后使用ImageText创建了一个分享的样式,调用sheet弹窗方法打开弹窗,弹窗的内容为我们声明好的ShareSheet视图,然后将声明好的内容传入进行分享。效果如下:

12.png

8、如何在按钮点击时有震动反馈?

iOS很突出的一点是它的线性马达所带来的反馈体验,让我们在点击屏幕某些操作时能够接收到App提供的反馈信息。

如果我们需要给App的某些操作加入一些震动反馈,该如何实现?

我们可以使用UINotificationFeedbackGenerator来实现震动反馈的效果,示例:

struct Haptics {
    static func hapticSuccess() {
        let generator = UINotificationFeedbackGenerator()
        generator.notificationOccurred(.success)
    }

    static func hapticWarning() {
        let generator = UINotificationFeedbackGenerator()
        generator.notificationOccurred(.warning)
    }
}

上述代码中,我们创建了一个结构体Haptics,在Haptics中定义了2个震动反馈效果,一个时成功反馈,一个是失败反馈。

然后我们在实际业务视图中使用它,示例:

struct HapticsView: View {
    var body: some View {

        VStack(spacing:40) {
            Text("成功时的反馈")
                .padding()
                .foregroundColor(.white)
                .background(Color.green)
                .cornerRadius(5)
                .onTapGesture {
                    Haptics.hapticSuccess()
                }

            Text("失败时的反馈")
                .padding()
                .foregroundColor(.white)
                .background(Color.gray)
                .cornerRadius(5)
                .onTapGesture {
                    Haptics.hapticWarning()
                }
        }
    }
}

13.png

上述代码中,我们创建了2个按钮,分别赋予了不同的样式,当我们点击按钮时,会调用震动反馈的方法,从而实现让用户有点击的效果。

震动反馈常用在长按或者一些警告业务场景中,可以视情况而使用。

小结

好啦!这就是本章的所有内容,是不是有点眼前一亮呢?

你还知道有哪些SwiftUI小技巧,不妨分享一下。

如果本专栏对你有帮助,不妨点赞、评论、关注~

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿