SwiftUI极简教程40:构建SearchBar搜索栏和TabView底部导航

简介: 在本章中,你将学会构建Search搜索进行列表搜索和TabView底部导航。在上一章节中,我们完成了一个简单的ColourAtla色卡App,接下来我们继续完善App的相关内容。

image.png

SearchBar搜索栏

首先是SearchBar搜索栏,搜索栏的作用是根据列表的内容进行检索,找出我们需要的色卡。

我们使用TextField输入框来构建SearchBar搜索栏,我们先声明一个变量来存储我们的搜索内容。示例:

@State var search = ""
复制代码

然后构建SearchBar搜索栏的样式。示例:

// MARK: 搜索
private var SearchBarView: some View {
    TextField("搜索颜色值", text: $search)
        .padding(7)
        .padding(.horizontal, 25)
        .background(Color(.systemGray6))
        .cornerRadius(8)
        .overlay(
            Image(systemName: "magnifyingglass")
                .foregroundColor(.gray)
                .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                .padding(.leading, 8)
        )
        .padding(.horizontal, 10)
}
复制代码

上述代码中,我们构建了一个新的视图SearchBarView,使用TextField输入框作为搜索栏,然后绑定search内容,然后使用修饰符完善了SearchBar搜索栏的样式。我们先替换原有的CardTitleView看看效果:

image.png

搜索方法

为了实现搜索颜色名称的交互,我们需要提供一个方法,搜索列表中的色卡。示例:

// MARK: 搜索颜色方法
func searchColor() {
    let query = search.lowercased()
    DispatchQueue.global(qos: .background).async {
        let filter = cardItems.filter { $0.cardColorRBG.lowercased().contains(query) }
        DispatchQueue.main.async {
            withAnimation(.spring()) {
                self.cardItems = filter
            }
        }
    }
}
复制代码

上述代码中,我们创建了一个搜索颜色的方法searchColor,通过根据搜索文字内容search,查找cardItems色卡数组中的cardColorRBG卡片颜色值参数,如果匹配成功,就在cardItems色卡数组中找到并展示这个颜色。

我们在SearchBarView视图中,当我们TextField输入框内容变化时调用这个方法。示例:

.onChange(of: search) { _ in
    if search != "" {
        searchColor()
    } else {
        search = ""
        getColors()
    }
}

image.png

搜索栏切换

接下来,我们来实现标题栏搜索栏切换

我们尝试在标题栏右侧加入一个搜索图标,点击搜索图标切换到搜索栏,在搜索栏输入框右侧也增加一个取消按钮,点击取消又回到标题栏中。

先声明一个存储变量showSearchBar用于判断切换状态。

@State var showSearchBar = false
复制代码

然后构建搜索按钮的样式和取消按钮的样式。示例:

// MARK: 搜索icon
private var SearchButtonView: some View {
    Button(action: {
        withAnimation(.easeOut) {
            showSearchBar.toggle()
        }
    }, label: {
        Image(systemName: "magnifyingglass")
            .font(.system(size: 20, weight: .bold))
            .foregroundColor(.gray)
    })
}
// MARK: 取消按钮
private var CloseButtonView: some View {
    Button(action: {
        withAnimation(.easeOut) {
            search = ""
            getColors()
            showSearchBar.toggle()
        }
    }, label: {
        Text("取消")
            .foregroundColor(.gray)
    })
}


image.png

上述代码中,我们创建了两个视图SearchButtonViewCloseButtonView。

SearchButtonView视图中,我们使用系统搜索图标做一个搜索按钮操作,点击时更改showSearchBar的状态。

CloseButtonView视图中,我们使用文字按钮做一个取消按钮的操作,点击时清空输入框的内容search,并且更改showSearchBar的状态,同时调用getColors获取颜色的方法。

完成这些后,我们进行样式的组装,示例:

// MARK: 搜索切换
private var SwitchSearchBar: some View {
    HStack(spacing: 20) {
        if showSearchBar {
            SearchBarView
            CloseButtonView
        } else {
            CardTitleView
            Spacer()
            SearchButtonView
        }
    }
    .padding(.top, 20)
    .padding(.bottom, 10)
    .padding(.horizontal)
    .zIndex(1)
}
复制代码

上述代码中,我们构建了一个新的视图SwitchSearchBar

SwitchSearchBar视图中,我们根据showSearchBar的状态切换展示搜索栏还是标题栏的内容,并把SwitchSearchBar视图在ContentView主视图中呈现。

我们预览下效果:

image.png

TabView底部导航

我们创建一个新的SwiftUI文件,命名为TabberView

struct TabberView: View {
    @State private var selectedTab = 0
    var body: some View {
        TabView(selection: $selectedTab) {
            ContentView()
                .tabItem {
                    if self.selectedTab == 0 {
                        Image(systemName: "house")
                    } else {
                        Image(systemName: "house.fill")
                    }
                    Text("首页")
                }
                .tag(0)
            Text("我的")
                .tabItem {
                    if self.selectedTab == 1 {
                        Image(systemName: "person")
                    } else {
                        Image(systemName: "person.fill")
                    }
                    Text("我的")
                }
                .tag(1)
        }
        .accentColor(Color.Hex(0x409EFF))
    }
}
复制代码

上述代码中,我们使用TabView来构建底部导航。

我们声明一个变量selectedTab来跟踪当前选中的是哪一个菜单,然后在TabView中绑定selectedTab的值。我们使用tabItem修饰符来显示当前菜单的内容,并且根据 selectedTab选中的状态修饰底部菜单的图标文字

最后我们给选中的菜单加上accentColor选中颜色。

我们预览下效果:

image.png

我们把之前章节完成的MineView我的视图也换到TabView底部菜单中,预览看下效果:

image.png

LoadingView加载动画

加载样式

之前我们使用ProgressView作为加载中的缺省动画,作为一个ColourAtla色卡App,使用ProgressView作为加载动画,这不够优雅

我们可以使用SwiftUI官方的rotationEffect修饰符构建一个加载动画,先创建一个新的SwiftUI文件,命名为LoadingView

首先声明一个变量存储旋转状态,然后构建一个旋转的图片icon

import SwiftUI
struct LoadingView: View {
    @State var show: Bool = false
    var body: some View {
        Image(systemName: "sun.min.fill")
            .resizable()
            .foregroundColor(Color.Hex(0xFAD0C4))
            .aspectRatio(contentMode: .fit)
            .frame(width: 60, height: 60)
            .rotationEffect(.degrees(show ? 360 : 0))
    }
}
复制代码

image.png

上述代码中,我们使用Image构建了一个加载的图标,然后使用rotationEffect修饰符根据show的状态进行旋转。

加载方法

为了让加载图标循环旋转,我们创建一个方法doAnimationshow的状态每1秒切换1次

func doAnimation() {
        withAnimation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)) {
            show.toggle()
        }
    }
复制代码

完成后,我们在Image展示时调用doAnimation的方法。

image.png

最后,我们在ContentViewLoadingView替换原来的ProgressView,然后查看下效果:

image.png

项目预览

image.png

快来动手试试吧!



相关文章
|
iOS开发
SwiftUI极简教程13:NavigationView导航栏使用
SwiftUI极简教程13:NavigationView导航栏使用
2387 2
SwiftUI极简教程13:NavigationView导航栏使用
|
存储 Swift
SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器
在本章中,你将学会使用Segment分段器、LazyVGrid垂直网格、ImagePicker图片选择器构建一个Logo生成器。 在上一章中,我们完善了SearchBar搜索栏、TabView底部导航,还有做了一个Loading加载动作。最近突然有个想法,如果把色卡和图片进行组合,这不就是一个简单的Logo了吗?我能不能做个Logo生成器? 说干就干,我们继续完成App的相关内容。
802 0
SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器
|
程序员 索引
SwiftUI极简教程18:SwipeCard卡片滑动效果的使用(上)
SwiftUI极简教程18:SwipeCard卡片滑动效果的使用(上)
1332 0
SwiftUI极简教程18:SwipeCard卡片滑动效果的使用(上)
|
搜索推荐 数据安全/隐私保护
颜值即正义,使用SwiftUI搭建个人信息、账号绑定、通用设置详情页
颜值即正义,使用SwiftUI搭建个人信息、账号绑定、通用设置详情页
338 0
|
vr&ar Swift
大师学SwiftUI第9章Part 1 - 异步并发之Task、Async、Await和错误
苹果系统借助现代处理器的多核可同步执行多条代码,提升同一时间内程序所能执行的任务。例如,一段代码从网上下载文件,另一段代码可以在屏幕上显示进度。此时,我们不能等待第一个执行完后再执行第二个,而必须要同步执行这两个任务。
458 0
|
iOS开发
加载中,加载中......使用SwiftUI设计2种Loading动画
加载中,加载中......使用SwiftUI设计2种Loading动画
650 0
|
Swift iOS开发 容器
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(一)(3)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(一)
332 0
|
iOS开发
scenePhase 的作用 -- 检测 APP 是否在后台
SwiftUI 提供了一个名为 `scenePhase` 的 环境变量,它在应用程序在前台、后台和非活动状态之间切换时会自动更新。你可以在 App 结构体本身或任何 SwiftUI 视图中观察这些状态的变化。
scenePhase 的作用 -- 检测 APP 是否在后台
|
存储 人机交互 API
8个SwiftUI的小技巧让隔壁同事两眼放光,直呼太卷了
在日常的SwiftUI开发过程中,常常会出现一些“小BUG”让我们措手不及、头顶发凉。这些问题可能是由于我们自己不熟悉SwiftUI语法导致的,也有是SwiftUI本身自带的缺陷,毕竟是一个新兴语言。 那么本章就介绍一些SwiftUI开发的小技巧,帮助我们避避那些让我们头秃的坑。
1363 0
8个SwiftUI的小技巧让隔壁同事两眼放光,直呼太卷了
|
存储 索引
SwiftUI极简教程12:List列表和ForEach循环的使用
SwiftUI极简教程12:List列表和ForEach循环的使用
1334 0
SwiftUI极简教程12:List列表和ForEach循环的使用