SwiftUI Minimalist Tutorial 40: Building SearchBar and TabView Bottom Navigation

foreword

In this chapter, you'll learn to build Searchsearches for list searches and TabViewbottom navigation.

In the previous chapter , we completed a simple ColourAtlacolor card App , and then we continue to improve Appthe related content.

SearchBar search bar

The first is the SearchBarsearch bar. The function of the search bar is to retrieve the content of the list to find the color card we need.

We use the TextFieldinput box to build SearchBarthe search bar, we start by declaring a variable to store our search content. Example:

@State var search = ""

Then SearchBarstyle the search bar. Example:

// 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)
}

In the above code, we build a new view SearchBarView, use the TextFieldinput box as the search bar, bind the searchcontent, and then use modifiers to refine the SearchBarstyle of the search bar. Let's replace the original to CardTitleViewsee the effect:

1.png

search method

In order to implement the interaction of searching for color names , we need to provide a method to search the color swatches in the list. Example:

// 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
            }
        }
    }
}

In the above code, we have created a method to search for color . By searching for the color value parameter of the card in the color card array searchColoraccording to the search text content search, if the match is successful , we will find and display the color in the color card array.cardItemscardColorRBGcardItems

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

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

2.png

上述代码中,我们在TextField输入框搜索内容search变量改变时,且search输入内容不为空时调用searchColor搜索颜色的方法,当search输入内容为空时,又重新调用getColors获取颜色的方法,这样,我们就实现了搜索颜色值的交互。

搜索栏切换

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

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

先声明一个存储变量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)
    })
}

3.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主视图中呈现。

我们预览下效果:

4.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选中颜色。

我们预览下效果:

5.png

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

6.png

LoadingView加载动画

加载样式

Previously we used it ProgressViewas the default animation in loading, as a ColourAtlacolor card App, and used it ProgressViewas the loading animation, which was not elegant enough .

We can build a loading animation using SwiftUIthe official rotationEffectmodifiers, by first creating a new SwiftUIfile named LoadingView.

First declare a variable to store the rotation state, then build a rotated picture 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))
    }
}

8.png

In the above code, we Imagebuild a loaded icon using the rotationEffectmodifier showand rotate it according to the state.

Load method

To make the loading icon rotate , we create a method doAnimationthat toggles showthe state every 1 second .

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

When done, the method we Imagecall when presenting doAnimation.

9.png

Finally, we ContentVieware replacing LoadingViewthe original with ProgressView, and then check the effect:

10.png

Project preview

7.png

Come and try it!

If this column is helpful to you, please like, comment, and follow~

I am participating in the recruitment of the creator signing program of the Nuggets Technology Community, click the link to register and submit .

Guess you like

Origin juejin.im/post/7117838599000686623