SwiftUI Minimalist Tutorial 40: Construcción de SearchBar y TabView Navegación inferior

prefacio

En este capítulo, aprenderá a crear Searchbúsquedas para búsquedas de lista y TabViewnavegación inferior.

En el capítulo anterior , completamos una ColourAtlaaplicación de tarjeta de color simple y luego continuamos mejorando Appel contenido relacionado.

Barra de búsqueda SearchBar

La primera es la SearchBarbarra de búsqueda.La función de la barra de búsqueda es recuperar el contenido de la lista para encontrar la carta de color que necesitamos.

Usamos el TextFieldcuadro de entrada para construir SearchBarla barra de búsqueda, comenzamos declarando una variable para almacenar nuestro contenido de búsqueda. Ejemplo:

@State var search = ""

Luego SearchBardiseñe la barra de búsqueda. Ejemplo:

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

En el código anterior, construimos una nueva vista SearchBarView, usamos el TextFieldcuadro de entrada como la barra de búsqueda, vinculamos el searchcontenido y luego usamos modificadores para refinar el SearchBarestilo de la barra de búsqueda. Reemplacemos el original para CardTitleViewver el efecto:

1.png

método de búsqueda

Para implementar la interacción de buscar nombres de colores , necesitamos proporcionar un método para buscar las muestras de color en la lista. Ejemplo:

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

En el código anterior, hemos creado un método para buscar color Al buscar el parámetro de valor de color de la tarjeta en la matriz de tarjetas de color de searchColoracuerdo con el contenido del texto de búsqueda search, si la coincidencia es exitosa , encontraremos y mostraremos el color en la matriz de tarjetas de color.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加载动画

加载样式

Anteriormente, ProgressViewla usábamos como animación predeterminada en la carga, como una ColourAtlatarjeta de color App, y ProgressViewla usábamos como animación de carga, que no era lo suficientemente elegante .

Podemos construir una animación de carga usando SwiftUIlos modificadores oficiales rotationEffect, creando primero un nuevo SwiftUIarchivo llamado LoadingView.

Primero declare una variable para almacenar el estado de rotación, luego construya una imagen rotada 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

En el código anterior, Imageconstruimos un ícono cargado usando el rotationEffectmodificador showy lo rotamos según el estado.

método de carga

Para hacer que el ícono de carga gire , creamos un método doAnimationque alterna showel estado cada 1 segundo .

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

Cuando haya terminado, el método que Imagellamamos al presentar doAnimation.

9.png

Finalmente, ContentViewreemplazamos LoadingViewel original con ProgressView, y luego verificamos el efecto:

10.png

Vista previa del proyecto

7.png

¡Ven y pruébalo!

Si esta columna es útil para usted, haga clic en Me gusta, comente y siga ~

Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .

Supongo que te gusta

Origin juejin.im/post/7117838599000686623
Recomendado
Clasificación