解决搜索页面键盘唤起的卡顿问题
This commit is contained in:
parent
3463e9b7b2
commit
1d12ff5625
@ -10,5 +10,23 @@
|
|||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</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>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -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()
|
|
||||||
//}
|
|
||||||
@ -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()
|
|
||||||
//}
|
|
||||||
@ -10,67 +10,146 @@ import SwiftData
|
|||||||
|
|
||||||
struct SearchView: View {
|
struct SearchView: View {
|
||||||
@Environment(\.modelContext) var modelContext
|
@Environment(\.modelContext) var modelContext
|
||||||
@State var showHistoryNum: Int = 2
|
|
||||||
|
|
||||||
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
@State var searchText: String = ""
|
@State var searchText: String = ""
|
||||||
|
|
||||||
@State var searchModel = SearchModel()
|
@State var searchModel = SearchModel()
|
||||||
|
|
||||||
|
@FocusState private var isFocused: Bool
|
||||||
|
@State private var isSearching = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack(spacing: 12) {
|
||||||
HStack(alignment: .center, spacing: 0) {
|
HStack(spacing: 12) {
|
||||||
Button(action: { dismiss() }) {
|
Button(action: { dismiss() }) {
|
||||||
Image(systemName: "chevron.left")
|
Image(systemName: "chevron.left")
|
||||||
.font(.system(size: 20, weight: .medium))
|
.font(.system(size: 20, weight: .medium))
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
HStack(spacing: 8) {
|
||||||
|
TextField("搜索...", text: $searchText)
|
||||||
SearchBar(searchText: $searchText, placeholder: "搜索...") {
|
.focused($isFocused)
|
||||||
let trimmedSearchText = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
|
.textFieldStyle(PlainTextFieldStyle())
|
||||||
if !trimmedSearchText.isEmpty {
|
.padding(8)
|
||||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
.background(Color(.systemGray6))
|
||||||
Task.detached {
|
.cornerRadius(8)
|
||||||
await searchModel.search(userId: userId, name: trimmedSearchText)
|
.submitLabel(.search)
|
||||||
|
.textInputAutocapitalization(.never)
|
||||||
|
.disableAutocorrection(true)
|
||||||
|
.keyboardType(.default)
|
||||||
|
.onSubmit {
|
||||||
|
doSearch()
|
||||||
|
}
|
||||||
|
.overlay(alignment: .trailing) {
|
||||||
|
Button(action: {
|
||||||
|
searchText = ""
|
||||||
|
}) {
|
||||||
|
Image(systemName: "multiply.circle.fill")
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.padding(.trailing, 8)
|
||||||
|
}
|
||||||
|
.opacity(isSearching ? 1 : 0)
|
||||||
|
.disabled(!isSearching)
|
||||||
}
|
}
|
||||||
|
|
||||||
// let historyModel = SearchHistory(keyword: trimmedSearchText, timestamp: Date())
|
Button {
|
||||||
// modelContext.insert(historyModel)
|
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)
|
.frame(height: 50)
|
||||||
.padding([.top, .bottom], 8)
|
.padding(.top, 12)
|
||||||
|
|
||||||
if searchModel.dramaGroups.count > 0 {
|
if searchModel.dramaGroups.isEmpty {
|
||||||
|
Spacer()
|
||||||
|
Text("什么都没有找到")
|
||||||
|
.font(.system(size: 18))
|
||||||
|
.foregroundColor(Color(hex: "#333333"))
|
||||||
|
Spacer()
|
||||||
|
} else {
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
// 基于日期的更新列表
|
|
||||||
LazyVStack(alignment: .center, spacing: 10) {
|
LazyVStack(alignment: .center, spacing: 10) {
|
||||||
ForEach(searchModel.dramaGroups, id: \.group_id) { group in
|
ForEach(searchModel.dramaGroups, id: \.group_id) { group in
|
||||||
SearchDramaGroupView(group: group)
|
SearchDramaGroupView(group: group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.top, 8)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Text("什么都没有找到")
|
|
||||||
.font(.system(size: 18))
|
|
||||||
.foregroundColor(Color(hex: "#333333"))
|
|
||||||
.frame(alignment: .center)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.navigationTitle("")
|
.navigationTitle("")
|
||||||
.navigationBarBackButtonHidden(true)
|
.navigationBarBackButtonHidden(true)
|
||||||
.padding(8)
|
.padding(.horizontal, 12)
|
||||||
.ignoresSafeArea(edges: .bottom)
|
.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 {
|
extension SearchView {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user