Я пытаюсь реализовать складной заголовок в Swiftui, который рушится, когда пользователь прокручивается и расширяется, когда пользователь прокручивает вверх. Пользователь перетаскивает представление сверху (притягивает к стилю обновления), а затем выпускается, заголовок исчезает /неожиданно скрывается.public struct CollapsibleHeaderList: View {
// MARK: - Private Vars
private let items = Array(0.. Bool {
guard let lastAnimationDate else {
return true
}
return abs(lastAnimationDate.timeIntervalSinceNow) > animationDuration
}
}
public enum HeaderState {
case initial
case collapse
case expand
}
public class CollapsibleHeaderViewModel: ObservableObject {
@Published private(set) public var state: HeaderState
private var indexSubject = PassthroughSubject()
private var cancellables = Set()
init() {
self.state = .initial
setupCollapsibleHeaderListener()
}
public func onCellAppear(index: Int) {
indexSubject.send(index)
}
private func setupCollapsibleHeaderListener() {
indexSubject
.throttle(for: .seconds(0.5), scheduler: DispatchQueue.main, latest: true)
.withPrevious()
.map { (previous, current) in
if let previous, previous < current {
return .collapse
} else {
return .expand
}
}
.removeDuplicates()
.sink { [weak self] headerState in
self?.state = headerState
}.store(in: &cancellables)
}
}
extension Publisher {
/// Includes the current element as well as the previous element from the upstream publisher in a tuple where the previous element is optional.
/// The first time the upstream publisher emits an element, the previous element will be `nil`.
/// This code was copied from https://stackoverflow.com/questions/639 ... ng-combine
///
/// let range = (1...5)
/// cancellable = range.publisher
/// .withPrevious()
/// .sink { print ("(\($0.previous), \($0.current))", terminator: " ") }
/// // Prints: "(nil, 1) (Optional(1), 2) (Optional(2), 3) (Optional(3), 4) (Optional(4), 5) ".
///
/// - Returns: A publisher of a tuple of the previous and current elements from the upstream publisher.
public func withPrevious() -> AnyPublisher {
scan(Optional.none) { ($0?.1, $1) }
.compactMap { $0 }
.eraseToAnyPublisher()
}
}
Вопрос:
Как я могу предотвратить скрытие заголовка, когда пользователь снимается с вершины? Кроме того, когда представление появляется в первый раз, заголовок не виден - он немедленно исчезает. < /P>
Вот запись экрана: запись экрана 2 < /p>
Вот код mycurrent: < /p>
@State private var showingHeader = true
var body: some View {
ZStack {
Color.backgroundColor3
.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
if showingHeader {
GlobalContactsFilterView(viewModel: viewModel)
.frame(height: 60)
.transition(
.asymmetric(
insertion: .push(from: .top),
removal: .push(from: .bottom)
)
)
}
if viewModel.isRefreshing {
VStack {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
.frame(maxWidth: .infinity)
.padding(.top, 10)
}
if viewModel.contacts.isEmpty && !viewModel.isLoading && !viewModel.isRefreshing {
NoDataView()
} else {
GeometryReader { outer in
let outerHeight = outer.size.height
ScrollView(.vertical) {
LazyVStack {
ForEach(Array(viewModel.contacts.enumerated()), id: \.element.id) { index, contact in
VStack(alignment: .leading) {
VStack {
VStack(spacing: 12) {
if contactVisibleFields.contains(.firstName) {
ContactDetailField(title: Strings.firstName, text: contact.firstName, textFont: .system(size: 13, weight: .semibold))
}
Rectangle()
.fill(.clear)
.frame(maxWidth: .infinity, maxHeight: 1)
}
.padding(.top, 10)
}
.frame(maxWidth: .infinity)
.background(.backgroundColor2)
.padding(.bottom, 3)
}
.frame(maxWidth: .infinity)
.background(index == viewModel.contacts.count - 1 ? Color.clear : Color.filterBarBackground)
.padding(.bottom, index == viewModel.contacts.count - 1 ? 50 : 0)
}
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
HStack {
Spacer()
if viewModel.isLoading && !viewModel.isRefreshing {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
} else {
Color.clear
.frame(height: 1)
.onAppear {
if let _ = clerk.user {
viewModel.fetchContacts()
}
}
}
Spacer()
}
.frame(maxWidth: .infinity)
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
}
.background {
GeometryReader { proxy in
let contentHeight = proxy.size.height
let minY = max(
min(0, proxy.frame(in: .named("ScrollView")).minY),
outerHeight - contentHeight
)
Color.clear
.onChange(of: minY) { oldVal, newVal in
if (showingHeader && newVal < oldVal) || !showingHeader && newVal > oldVal {
showingHeader = newVal > oldVal
}
}
}
}
}
.coordinateSpace(name: "ScrollView")
}
.padding(.top, 1)
}
}
//.frame(maxHeight: .infinity, alignment: .top)
.animation(.easeInOut, value: showingHeader)
Подробнее здесь: https://stackoverflow.com/questions/797 ... wn-gesture
Swiftui складные шкуры заголовка после выпуска жеста ⇐ IOS
Программируем под IOS
-
Anonymous
1756452056
Anonymous
Я пытаюсь реализовать складной заголовок в Swiftui, который рушится, когда пользователь прокручивается и расширяется, когда пользователь прокручивает вверх. Пользователь перетаскивает представление сверху (притягивает к стилю обновления), а затем выпускается, заголовок исчезает /неожиданно скрывается.public struct CollapsibleHeaderList: View {
// MARK: - Private Vars
private let items = Array(0.. Bool {
guard let lastAnimationDate else {
return true
}
return abs(lastAnimationDate.timeIntervalSinceNow) > animationDuration
}
}
public enum HeaderState {
case initial
case collapse
case expand
}
public class CollapsibleHeaderViewModel: ObservableObject {
@Published private(set) public var state: HeaderState
private var indexSubject = PassthroughSubject()
private var cancellables = Set()
init() {
self.state = .initial
setupCollapsibleHeaderListener()
}
public func onCellAppear(index: Int) {
indexSubject.send(index)
}
private func setupCollapsibleHeaderListener() {
indexSubject
.throttle(for: .seconds(0.5), scheduler: DispatchQueue.main, latest: true)
.withPrevious()
.map { (previous, current) in
if let previous, previous < current {
return .collapse
} else {
return .expand
}
}
.removeDuplicates()
.sink { [weak self] headerState in
self?.state = headerState
}.store(in: &cancellables)
}
}
extension Publisher {
/// Includes the current element as well as the previous element from the upstream publisher in a tuple where the previous element is optional.
/// The first time the upstream publisher emits an element, the previous element will be `nil`.
/// This code was copied from https://stackoverflow.com/questions/63926305/combine-previous-value-using-combine
///
/// let range = (1...5)
/// cancellable = range.publisher
/// .withPrevious()
/// .sink { print ("(\($0.previous), \($0.current))", terminator: " ") }
/// // Prints: "(nil, 1) (Optional(1), 2) (Optional(2), 3) (Optional(3), 4) (Optional(4), 5) ".
///
/// - Returns: A publisher of a tuple of the previous and current elements from the upstream publisher.
public func withPrevious() -> AnyPublisher {
scan(Optional.none) { ($0?.1, $1) }
.compactMap { $0 }
.eraseToAnyPublisher()
}
}
[b] Вопрос: [/b]
Как я могу предотвратить скрытие заголовка, когда пользователь снимается с вершины? Кроме того, когда представление появляется в первый раз, заголовок не виден - он немедленно исчезает. < /P>
Вот запись экрана: запись экрана 2 < /p>
Вот код mycurrent: < /p>
@State private var showingHeader = true
var body: some View {
ZStack {
Color.backgroundColor3
.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
if showingHeader {
GlobalContactsFilterView(viewModel: viewModel)
.frame(height: 60)
.transition(
.asymmetric(
insertion: .push(from: .top),
removal: .push(from: .bottom)
)
)
}
if viewModel.isRefreshing {
VStack {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
.frame(maxWidth: .infinity)
.padding(.top, 10)
}
if viewModel.contacts.isEmpty && !viewModel.isLoading && !viewModel.isRefreshing {
NoDataView()
} else {
GeometryReader { outer in
let outerHeight = outer.size.height
ScrollView(.vertical) {
LazyVStack {
ForEach(Array(viewModel.contacts.enumerated()), id: \.element.id) { index, contact in
VStack(alignment: .leading) {
VStack {
VStack(spacing: 12) {
if contactVisibleFields.contains(.firstName) {
ContactDetailField(title: Strings.firstName, text: contact.firstName, textFont: .system(size: 13, weight: .semibold))
}
Rectangle()
.fill(.clear)
.frame(maxWidth: .infinity, maxHeight: 1)
}
.padding(.top, 10)
}
.frame(maxWidth: .infinity)
.background(.backgroundColor2)
.padding(.bottom, 3)
}
.frame(maxWidth: .infinity)
.background(index == viewModel.contacts.count - 1 ? Color.clear : Color.filterBarBackground)
.padding(.bottom, index == viewModel.contacts.count - 1 ? 50 : 0)
}
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
HStack {
Spacer()
if viewModel.isLoading && !viewModel.isRefreshing {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
} else {
Color.clear
.frame(height: 1)
.onAppear {
if let _ = clerk.user {
viewModel.fetchContacts()
}
}
}
Spacer()
}
.frame(maxWidth: .infinity)
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
}
.background {
GeometryReader { proxy in
let contentHeight = proxy.size.height
let minY = max(
min(0, proxy.frame(in: .named("ScrollView")).minY),
outerHeight - contentHeight
)
Color.clear
.onChange(of: minY) { oldVal, newVal in
if (showingHeader && newVal < oldVal) || !showingHeader && newVal > oldVal {
showingHeader = newVal > oldVal
}
}
}
}
}
.coordinateSpace(name: "ScrollView")
}
.padding(.top, 1)
}
}
//.frame(maxHeight: .infinity, alignment: .top)
.animation(.easeInOut, value: showingHeader)
Подробнее здесь: [url]https://stackoverflow.com/questions/79749838/swiftui-collapsible-header-hides-after-pull-down-gesture[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия