Изменение цвета при нажатии на изображение значка (SwiftUI)

Не могу понять, как изменить цвет значка изображения после нажатия на него, например, если окно активно, то цвет значка синий, если нет, то серый.

Изменение цвета при нажатии на изображение значка (SwiftUI)

вот пример того, что я спрашиваю Изменение цвета при нажатии на изображение значка (SwiftUI)

Если вы знаете решение, пожалуйста, помогите мне

Вот полный код Этот код полностью рабочий, можете проверить

import SwiftUI

struct AllLinesView: View {
   
    @State var currentSelection: Int = 0 
    var body: some View { 
        PagerTabView(tint: .white, selection: $currentSelection) {     
            Image(systemName: "bolt.fill")
                .pageLabel()
            
            Image(systemName: "flame")
                .pageLabel()
            
            Image(systemName: "person.fill")
                .pageLabel()
   
        } content: {
            
            Color.red
                .pageView(ignoresSafeArea: true, edges: .bottom)
       
            Color.green
                .pageView(ignoresSafeArea: true, edges: .bottom)
                
            Color.yellow
                .pageView(ignoresSafeArea: true, edges: .bottom)
            
        }
        .ignoresSafeArea(.container, edges: .bottom)
  
    }
}

TabView

struct PagerTabView<Content: View, Label: View>: View {
    var content: Content
    var label: Label
    var tint: Color
    @Binding var selection: Int
    
    init(tint:Color,selection: Binding<Int>,@ViewBuilder labels: @escaping ()->Label,@ViewBuilder content: @escaping ()->Content) {
        self.content = content()
        self.label = labels()
        self.tint = tint
        self._selection = selection
    }
    
    @State var offset: CGFloat = 0
    @State var maxTabs: CGFloat = 0
    @State var tabOffset: CGFloat = 0
    
    var body: some View {
        
        VStack(alignment: .leading,spacing: 0) {

            HStack(spacing: 0) {
                label
            }
            .overlay(
            
                HStack(spacing: 0) {
                    ForEach(0..<Int(maxTabs), id: \.self) { index in
                        Rectangle()
                            .fill(Color.black.opacity(0.01))
                            .onTapGesture {
                                let newOffset = CGFloat(index) * getScreenBounds().width
                                self.offset = newOffset

                            }
                    }
                }
            
            )
            .foregroundColor(tint)
            Capsule()
                .fill(tint)
                .frame(width: maxTabs == 0 ? 0 : (getScreenBounds().width / maxTabs), height: 2)
                .padding(.top, 10)
                .frame(maxWidth: .infinity, alignment: .leading)
                .offset(x: tabOffset)
 
            OffsetPageTabView(selection: $selection,offset: $offset) {
                HStack(spacing: 0) {
                    content
                }
                .overlay(
                
                    GeometryReader { proxy in
                        
                        Color.clear
                            .preference(key: TabPreferenceKey.self, value: proxy.frame(in: .global))
                        
                    }  
                )
                .onPreferenceChange(TabPreferenceKey.self) { proxy in
                    let minX = -proxy.minX
                    let maxWidth = proxy.width
                    let screenWidth = getScreenBounds().width
                    let maxTabs = (maxWidth / screenWidth).rounded()
                    
                    let progress = minX / screenWidth
                    let tabOffset = progress * (screenWidth / maxTabs)
                    
                    self.tabOffset = tabOffset
                    
                    self.maxTabs = maxTabs
                }
            }
        }
    }
}

TabPreferenceKey

struct TabPreferenceKey: PreferenceKey {
    
    static var defaultValue: CGRect = .init()
    
    static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
        value = nextValue()
    }
    
}

pageLabel — просмотр страницы

extension View {
    
    //IMAGE
    func pageLabel()->some View {
        self
            .frame(maxWidth: .infinity, alignment: .center)
    }
    //PAGE
    func pageView(ignoresSafeArea: Bool = false, edges: Edge.Set = [])->some View {
        self
            .frame(width: getScreenBounds().width, alignment: .center)
            .ignoresSafeArea(ignoresSafeArea ? .container : .init(), edges: edges)
    }
    
    func getScreenBounds()->CGRect {
        return UIScreen.main.bounds
    }
    
}

Смещение страницы

struct OffsetPageTabView<Content: View>: UIViewRepresentable {
    
    var content: Content
    @Binding var offset: CGFloat
    @Binding var selection: Int

    func makeCoordinator() -> Coordinator {
        return OffsetPageTabView.Coordinator(parent: self)
    }
    
    init(selection: Binding<Int>,offset: Binding<CGFloat>, @ViewBuilder content: @escaping ()->Content) {
        
        self.content = content()
        self._offset = offset
        self._selection = selection
    }
    
    func makeUIView(context: Context) -> UIScrollView {
        
        let scrollview = UIScrollView()
        let hostview = UIHostingController(rootView: content)
        hostview.view.translatesAutoresizingMaskIntoConstraints = false
        
        let constraints = [
        
            hostview.view.topAnchor.constraint(equalTo: scrollview.topAnchor),
            hostview.view.leadingAnchor.constraint(equalTo: scrollview.leadingAnchor),
            hostview.view.trailingAnchor.constraint(equalTo: scrollview.trailingAnchor),
            hostview.view.bottomAnchor.constraint(equalTo: scrollview.bottomAnchor),
            
            hostview.view.heightAnchor.constraint(equalTo: scrollview.heightAnchor)
            
        ]
        
        scrollview.addSubview(hostview.view)
        scrollview.addConstraints(constraints)
        
        scrollview.isPagingEnabled = true
        scrollview.showsVerticalScrollIndicator = false
        scrollview.showsHorizontalScrollIndicator = false
        
        scrollview.delegate = context.coordinator
        
        return scrollview
    }
    
    func updateUIView(_ uiView: UIScrollView, context: Context) {
        let currentOffset = uiView.contentOffset.x
        
        if currentOffset != offset {
            print("updating")
            uiView.setContentOffset(CGPoint(x: offset, y: 0), animated: true)
        }
    }
    
    class Coordinator: NSObject, UIScrollViewDelegate {
        
        var parent: OffsetPageTabView
        
        init(parent: OffsetPageTabView) {
            self.parent = parent
            
        }
        
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let offset = scrollView.contentOffset.x
            
            let maxSize = scrollView.contentSize.width
            let currentSelection = (offset / maxSize).rounded()
            parent.selection = Int(currentSelection)
            
            parent.offset = offset
        }
    }
}

Можете ли вы предоставить минимальный воспроизводимый пример для интерфейса, на который вы ссылаетесь? В противном случае будет сложно предоставить решение, которое гарантированно будет работать с вашей настройкой.

jnpdx 18.03.2022 18:39

Смотрел видео, а там не маленький код, не могу сюда отправить

Dmitriy 18.03.2022 18:42

Пожалуйста, поделитесь своим кодом, это будет лучше всего помочь вам

FBarıs2020 18.03.2022 18:52

Если у вас есть время, посмотрите видео, я не могу разместить этот код здесь, потому что он большой.

Dmitriy 18.03.2022 20:18

Вам не нужно публиковать все кода из видео — достаточно минимальный воспроизводимый пример, как указано выше. Крайне маловероятно, что кто-то пойдет и посмотрит видео и воспроизведет все кода, которого, как вы упомянули, может быть совсем немного, чтобы попытаться ответить на этот вопрос.

jnpdx 18.03.2022 20:54

Я отредактировал свой вопрос и добавил код, пожалуйста, посмотрите

Dmitriy 18.03.2022 22:08

дубликат, см. этот пост SO: stackoverflow.com/questions/60803755/…

workingdog support Ukraine 19.03.2022 00:14

Какой дубликат?! Это два разных вопроса.

Dmitriy 19.03.2022 02:31

@jnpdx я написал полный код

Dmitriy 19.03.2022 14:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Этот код не построен таким образом, чтобы его можно было легко изменить. Основная проблема заключается в том, что он использует ViewBuilder для меток и страниц, но наш (не Apple) код SwiftUI не имеет представления о том, сколько элементов передается в такой ViewBuilder. Итак, мне пришлось добавить несколько уродливый хак для передачи числа дочерних просмотров вручную. Мне также пришлось добавить модификаторы foregroundColor явно для каждой метки, что является еще одним результатом недостатков работы существующего кода.

Логика currentSelection исходного кода была полностью нарушена (т. е. вообще не функционировала), но ее легко исправить после явной передачи количества дочерних элементов.

См. обновленный код, включая встроенные комментарии о том, где были внесены изменения.

struct AllLinesView: View {
   
    @State var currentSelection: Int = 0
    var body: some View {
        PagerTabView(tint: .white, selection: $currentSelection, children: 3) { //<-- Here
            Image(systemName: "bolt.fill")
                .pageLabel()
                .foregroundColor(currentSelection == 0 ? .blue : .white) //<-- Here
            
            Image(systemName: "flame")
                .pageLabel()
                .foregroundColor(currentSelection == 1 ? .blue : .white) //<-- Here
            
            Image(systemName: "person.fill")
                .pageLabel()
                .foregroundColor(currentSelection == 2 ? .blue : .white) //<-- Here
   
        } content: {
            
            Color.red
                .pageView(ignoresSafeArea: true, edges: .bottom)
       
            Color.green
                .pageView(ignoresSafeArea: true, edges: .bottom)
                
            Color.yellow
                .pageView(ignoresSafeArea: true, edges: .bottom)
            
        }
        .ignoresSafeArea(.container, edges: .bottom)
        .onChange(of: currentSelection) { newValue in
            print(newValue)
        }
    }
}

struct PagerTabView<Content: View, Label: View>: View {
    var content: Content
    var label: Label
    var tint: Color
    var children: Int //<-- Here
    @Binding var selection: Int
    
    init(tint:Color,selection: Binding<Int>,children: Int, @ViewBuilder labels: @escaping ()->Label,@ViewBuilder content: @escaping ()->Content) {
        self.children = children
        self.content = content()
        self.label = labels()
        self.tint = tint
        self._selection = selection
    }
    
    @State var offset: CGFloat = 0
    @State var maxTabs: CGFloat = 0
    @State var tabOffset: CGFloat = 0
    
    var body: some View {
        
        VStack(alignment: .leading,spacing: 0) {

            HStack(spacing: 0) {
                label
            }
            .overlay(
            
                HStack(spacing: 0) {
                    ForEach(0..<Int(maxTabs), id: \.self) { index in
                        Rectangle()
                            .fill(Color.black.opacity(0.01))
                            .onTapGesture {
                                let newOffset = CGFloat(index) * getScreenBounds().width
                                self.offset = newOffset
                            }
                    }
                }
            
            )
            .foregroundColor(tint)
            Capsule()
                .fill(tint)
                .frame(width: maxTabs == 0 ? 0 : (getScreenBounds().width / maxTabs), height: 2)
                .padding(.top, 10)
                .frame(maxWidth: .infinity, alignment: .leading)
                .offset(x: tabOffset)
 
            OffsetPageTabView(selection: $selection,offset: $offset, children: children) { //<-- Here
                HStack(spacing: 0) {
                    content
                }
                .overlay(
                
                    GeometryReader { proxy in
                        
                        Color.clear
                            .preference(key: TabPreferenceKey.self, value: proxy.frame(in: .global))
                        
                    }
                )
                .onPreferenceChange(TabPreferenceKey.self) { proxy in
                    let minX = -proxy.minX
                    let maxWidth = proxy.width
                    let screenWidth = getScreenBounds().width
                    let maxTabs = (maxWidth / screenWidth).rounded()
                    
                    let progress = minX / screenWidth
                    let tabOffset = progress * (screenWidth / maxTabs)
                    
                    self.tabOffset = tabOffset
                    
                    self.maxTabs = maxTabs
                }
            }
        }
    }
}

struct TabPreferenceKey: PreferenceKey {
    
    static var defaultValue: CGRect = .init()
    
    static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
        value = nextValue()
    }
    
}

extension View {
    
    //IMAGE
    func pageLabel()->some View {
        self
            .frame(maxWidth: .infinity, alignment: .center)
    }
    //PAGE
    func pageView(ignoresSafeArea: Bool = false, edges: Edge.Set = [])->some View {
        self
            .frame(width: getScreenBounds().width, alignment: .center)
            .ignoresSafeArea(ignoresSafeArea ? .container : .init(), edges: edges)
    }
    
    func getScreenBounds()->CGRect {
        return UIScreen.main.bounds
    }
    
}

struct OffsetPageTabView<Content: View>: UIViewRepresentable {
    
    var content: Content
    @Binding var offset: CGFloat
    @Binding var selection: Int
    var children: Int //<-- Here

    func makeCoordinator() -> Coordinator {
        return OffsetPageTabView.Coordinator(parent: self)
    }
    
    init(selection: Binding<Int>,offset: Binding<CGFloat>, children: Int, @ViewBuilder content: @escaping ()->Content) {
        
        self.content = content()
        self._offset = offset
        self._selection = selection
        self.children = children
    }
    
    func makeUIView(context: Context) -> UIScrollView {
        
        let scrollview = UIScrollView()
        let hostview = UIHostingController(rootView: content)
        hostview.view.translatesAutoresizingMaskIntoConstraints = false
        
        let constraints = [
        
            hostview.view.topAnchor.constraint(equalTo: scrollview.topAnchor),
            hostview.view.leadingAnchor.constraint(equalTo: scrollview.leadingAnchor),
            hostview.view.trailingAnchor.constraint(equalTo: scrollview.trailingAnchor),
            hostview.view.bottomAnchor.constraint(equalTo: scrollview.bottomAnchor),
            
            hostview.view.heightAnchor.constraint(equalTo: scrollview.heightAnchor)
            
        ]
        
        scrollview.addSubview(hostview.view)
        scrollview.addConstraints(constraints)
        
        scrollview.isPagingEnabled = true
        scrollview.showsVerticalScrollIndicator = false
        scrollview.showsHorizontalScrollIndicator = false
        
        scrollview.delegate = context.coordinator
        
        return scrollview
    }
    
    func updateUIView(_ uiView: UIScrollView, context: Context) {
        let currentOffset = uiView.contentOffset.x
        
        if currentOffset != offset {
            //print("updating")
            uiView.setContentOffset(CGPoint(x: offset, y: 0), animated: true)
        }
    }
    
    class Coordinator: NSObject, UIScrollViewDelegate {
        
        var parent: OffsetPageTabView
        
        init(parent: OffsetPageTabView) {
            self.parent = parent
            
        }
        
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let offset = scrollView.contentOffset.x
            
            let maxSize = scrollView.contentSize.width
            let currentSelection = (offset / maxSize) * CGFloat(parent.children) //<-- Here
            print("max: ", maxSize, offset)
            print("Set selection to: ", Int(currentSelection), currentSelection)
            parent.selection = Int(currentSelection)
            
            parent.offset = offset
        }
    }
}

Другие вопросы по теме