简体   繁体   English

单击图标图像更改颜色(SwiftUI)

[英]Change color on click on icon image (SwiftUI)

I can't figure out how to change the color of the image icon after clicking on it, for example, if the window is active, then the color of the icon is blue, if not, then it's gray.我无法弄清楚如何在单击后更改图像图标的颜色,例如,如果 window 处于活动状态,则图标的颜色为蓝色,否则为灰色。

在此处输入图像描述

here is an example of what i am asking这是我要问的一个例子在此处输入图像描述

If you know the solution please help me如果您知道解决方案,请帮助我

Here is the full code This code is fully working, you can check it out这是完整的代码这段代码完全可以工作,你可以检查一下

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 TabPreference键

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

pageLabel - pageView页面标签 - 页面视图

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

OffsetPage偏移页

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

This code is not built in a way that is easily changeable.此代码不是以易于更改的方式构建的。 The primary issue is that it uses ViewBuilder s for the labels and pages, but our (not Apple's) SwiftUI code doesn't have insight into how many elements get passed into a ViewBuilder like this.主要问题是它使用ViewBuilder作为标签和页面,但我们的(不是 Apple 的)SwiftUI 代码无法了解有多少元素像这样传递到ViewBuilder中。 So, I had to add a somewhat ugly hack of passing the number of child views by hand.所以,我不得不添加一个有点难看的 hack 来手动传递子视图的数量。 I also had to add foregroundColor modifiers explicitly for each label, which is another result of shortcomings of the way the existing code works.我还必须为每个 label 显式添加foregroundColor修饰符,这是现有代码工作方式存在缺陷的另一个结果。

The original code's currentSelection logic was completely broken (ie didn't function at all), but was easily fixable once explicitly passing the number of child elements.原始代码的currentSelection逻辑被完全破坏(即根本没有 function),但是一旦显式传递子元素的数量就很容易修复。

See updated code including inline comments of where changes were made.查看更新的代码,包括对更改位置的内联注释。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM