解决搜索页面键盘唤起的卡顿问题

This commit is contained in:
anlicheng 2025-06-08 00:04:17 +08:00
parent 3463e9b7b2
commit 1d12ff5625
4 changed files with 128 additions and 158 deletions

View File

@ -10,5 +10,23 @@
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>C85F58BF2D64D10F00D761E9</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>C85F58D12D64D11000D761E9</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>C85F58DB2D64D11000D761E9</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View File

@ -1,80 +0,0 @@
//
// SearchBar.swift
// dimensionhub
//
// Created by on 2025/4/8.
//
import SwiftUI
//
struct SearchBar: View {
@State private var isSearching = false
@Binding<String> var searchText: String
var placeholder: String
var onSearch: () -> Void
@FocusState private var isFocused: Bool
var body: some View {
//
HStack(alignment: .center, spacing: 8) {
//
TextField(placeholder, text: $searchText)
.textFieldStyle(PlainTextFieldStyle())
.keyboardType(.default)
.focused($isFocused)
.submitLabel(.search)
.onSubmit {
onSearch()
}
.contentShape(Rectangle())
.padding(8)
.background(Color(.systemGray6))
.cornerRadius(8)
.overlay(alignment: .trailing) {
HStack {
if isSearching {
Button(action: {
searchText = ""
}) {
Image(systemName: "multiply.circle.fill")
.foregroundColor(.gray)
.padding(.trailing, 8)
}
}
}
}
.frame(maxWidth: .infinity)
.onTapGesture {
isFocused = true
}
//
Button {
if !searchText.isEmpty {
onSearch()
}
} label: {
Text("搜索")
.font(.system(size: 18))
.foregroundColor(.gray)
}
.padding(.trailing, 10)
.disabled(searchText.isEmpty)
}
.onChange(of: searchText) {
isSearching = !searchText.trimmingCharacters(in: .whitespaces).isEmpty
}
.onAppear {
DispatchQueue.main.async {
isFocused = true
}
}
}
}
//#Preview {
// SearchBar()
//}

View File

@ -1,47 +0,0 @@
//
// SearchDramaGroupView.swift
// dimensionhub
//
// Created by on 2025/4/8.
//
import SwiftUI
//
struct SearchDramaGroupView: View {
let group: SearchModel.DramaGroup
var body: some View {
LazyVStack(alignment: .center, spacing: 10) {
ForEach(group.items, id: \.id) { item in
NavigationLink(destination: DetailView(id: item.id)) {
FlexImage(urlString: item.thumb, width: 370, height: 180, placeholder: "ph_img_big")
.frame(width: 370, height: 180)
.overlay(alignment: .topLeading) {
VStack(alignment: .leading, spacing: 8) {
Text(item.name)
.font(.system(size: 16))
.foregroundColor(.white)
.lineLimit(1)
Text(item.status)
.font(.system(size: 12))
.foregroundColor(.white)
.lineLimit(1)
}
.padding(5)
.background(
Color.black.opacity(0.6)
)
.cornerRadius(5)
.padding(8)
}
}
}
}
}
}
//#Preview {
// SearchDramaGroupView()
//}

View File

@ -10,67 +10,146 @@ import SwiftData
struct SearchView: View {
@Environment(\.modelContext) var modelContext
@State var showHistoryNum: Int = 2
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
@Environment(\.dismiss) var dismiss
@State var searchText: String = ""
@State var searchModel = SearchModel()
@FocusState private var isFocused: Bool
@State private var isSearching = false
var body: some View {
VStack {
HStack(alignment: .center, spacing: 0) {
VStack(spacing: 12) {
HStack(spacing: 12) {
Button(action: { dismiss() }) {
Image(systemName: "chevron.left")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.black)
}
Spacer()
SearchBar(searchText: $searchText, placeholder: "搜索...") {
let trimmedSearchText = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmedSearchText.isEmpty {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
Task.detached {
await searchModel.search(userId: userId, name: trimmedSearchText)
HStack(spacing: 8) {
TextField("搜索...", text: $searchText)
.focused($isFocused)
.textFieldStyle(PlainTextFieldStyle())
.padding(8)
.background(Color(.systemGray6))
.cornerRadius(8)
.submitLabel(.search)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.keyboardType(.default)
.onSubmit {
doSearch()
}
// let historyModel = SearchHistory(keyword: trimmedSearchText, timestamp: Date())
// modelContext.insert(historyModel)
.overlay(alignment: .trailing) {
Button(action: {
searchText = ""
}) {
Image(systemName: "multiply.circle.fill")
.foregroundColor(.gray)
.padding(.trailing, 8)
}
.opacity(isSearching ? 1 : 0)
.disabled(!isSearching)
}
Button {
if !searchText.isEmpty {
doSearch()
isFocused = false //
}
} label: {
Text("搜索")
.font(.system(size: 18))
.foregroundColor(.gray)
}
.padding(.trailing, 10)
.disabled(searchText.isEmpty)
}
.onChange(of: searchText) {
isSearching = !searchText.trimmingCharacters(in: .whitespaces).isEmpty
}
}
.frame(height: 50)
.padding([.top, .bottom], 8)
if searchModel.dramaGroups.count > 0 {
.padding(.top, 12)
if searchModel.dramaGroups.isEmpty {
Spacer()
Text("什么都没有找到")
.font(.system(size: 18))
.foregroundColor(Color(hex: "#333333"))
Spacer()
} else {
ScrollView(.vertical, showsIndicators: false) {
//
LazyVStack(alignment: .center, spacing: 10) {
ForEach(searchModel.dramaGroups, id: \.group_id) { group in
SearchDramaGroupView(group: group)
}
}
.padding(.top, 8)
}
} else {
Spacer()
Text("什么都没有找到")
.font(.system(size: 18))
.foregroundColor(Color(hex: "#333333"))
.frame(alignment: .center)
}
Spacer()
}
.navigationTitle("")
.navigationBarBackButtonHidden(true)
.padding(8)
.ignoresSafeArea(edges: .bottom)
.padding(.horizontal, 12)
.ignoresSafeArea(.keyboard, edges: .bottom) //
.onAppear {
//
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
isFocused = true
}
}
}
private func doSearch() {
let trimmed = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
Task.detached {
await searchModel.search(userId: userId, name: trimmed)
}
//
// let history = SearchHistory(keyword: trimmed, timestamp: Date())
// modelContext.insert(history)
}
}
}
//
struct SearchDramaGroupView: View {
let group: SearchModel.DramaGroup
var body: some View {
LazyVStack(alignment: .center, spacing: 10) {
ForEach(group.items, id: \.id) { item in
NavigationLink(destination: DetailView(id: item.id)) {
FlexImage(urlString: item.thumb, width: 370, height: 180, placeholder: "ph_img_big")
.frame(width: 370, height: 180)
.overlay(alignment: .topLeading) {
VStack(alignment: .leading, spacing: 8) {
Text(item.name)
.font(.system(size: 16))
.foregroundColor(.white)
.lineLimit(1)
Text(item.status)
.font(.system(size: 12))
.foregroundColor(.white)
.lineLimit(1)
}
.padding(5)
.background(
Color.black.opacity(0.6)
)
.cornerRadius(5)
.padding(8)
}
}
}
}
}
}
extension SearchView {