繁体   English   中英

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

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

我无法弄清楚如何在单击后更改图像图标的颜色,例如,如果 window 处于活动状态,则图标的颜色为蓝色,否则为灰色。

在此处输入图像描述

这是我要问的一个例子在此处输入图像描述

如果您知道解决方案,请帮助我

这是完整的代码这段代码完全可以工作,你可以检查一下

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

选项卡视图

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

TabPreference键

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

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

此代码不是以易于更改的方式构建的。 主要问题是它使用ViewBuilder作为标签和页面,但我们的(不是 Apple 的)SwiftUI 代码无法了解有多少元素像这样传递到ViewBuilder中。 所以,我不得不添加一个有点难看的 hack 来手动传递子视图的数量。 我还必须为每个 label 显式添加foregroundColor修饰符,这是现有代码工作方式存在缺陷的另一个结果。

原始代码的currentSelection逻辑被完全破坏(即根本没有 function),但是一旦显式传递子元素的数量就很容易修复。

查看更新的代码,包括对更改位置的内联注释。

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