UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: How to apply .onHover ( which uses @State ) to a single ViewModifer - in order to cause multiple Text views to behave the same, but activate independently ?

Forums > SwiftUI

I'm trying to make multiple Text views' .overlay (RoundedRectangle) change colours on mouse hovering. Each Text view needs to do so individually, though they all have the same behaviour ( the .overlay turns purple ). My code is based on @twostraws 's https://www.hackingwithswift.com/quick-start/swiftui/how-to-detect-the-user-hovering-over-a-view , which uses .onHover and @State private var :

It works, but unfortunately there are many blocks of identical code ( the only difference is the name of the @State private var - overText# )

import SwiftUI

struct myStyleEnglish: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding(10)
            .foregroundStyle(.cyan.opacity(0.8))
            .font(.custom("Georgia", size: 14))
    }
}

struct myStyleFrench: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding(10)
            .foregroundStyle(.pink.opacity(0.8))
            .font(.custom("Futura", size: 14))
    }
}

struct ContentView: View {

    @State private var overText1 = false
    @State private var overText2 = false
    @State private var overText3 = false
    @State private var overText4 = false
    // Many more @State lines πŸ˜”

    var body: some View {

        VStack(spacing: 10) {
            Text("πŸ—£οΈ LET'S LEARN FRENCH ! πŸ—£οΈ")
                .modifier(myStyleEnglish())
            HStack(spacing: 10) {
                Text("CALL THE FIRE DEPARTMENT !")
                    .modifier(myStyleEnglish())
                Text("APPELEZ LES POMPIERS !")
                    .modifier(myStyleFrench())
                    .overlay(
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(overText1 ? .purple.opacity(0.8) : .white.opacity(0.1))
                    )
                    .onHover { over in overText1 = over }
            }

            HStack(spacing: 10) {
                Text("CALL THE AMBULANCE !")
                    .modifier(myStyleEnglish())
                Text("APPELER L'AMBULANCE !")
                    .modifier(myStyleFrench())
                    .overlay(
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(overText2 ? .purple.opacity(0.8) : .white.opacity(0.1))
                    )
                    .onHover { over in overText2 = over }
            }

            HStack(spacing: 10) {
                Text("CALL THE POLICE !")
                    .modifier(myStyleEnglish())
                Text("APPELEZ LA POLICE !")
                    .modifier(myStyleFrench())
                    .overlay(
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(overText3 ? .purple.opacity(0.8) : .white.opacity(0.1))
                    )
                    .onHover { over in overText3 = over }
            }

            HStack(spacing: 10) {
                Text("CALL CARETAKER !")
                    .modifier(myStyleEnglish())
                Text("APPELEZ LE GARDIEN !")
                    .modifier(myStyleFrench())
                    .overlay(
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(overText4 ? .purple.opacity(0.8) : .white.opacity(0.1))
                    )
                    .onHover { over in overText4 = over }
            }
            // Many more HStacks 😰
        }
    }
}

#Preview {
    ContentView()
}

I am already using ViewModifier to reduce repeating codes, but Swift will not allow me to put the .onHover + .overlay + @State inside the ViewModifier :

import SwiftUI

struct myStyleEnglish: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding(10)
            .foregroundStyle(.cyan.opacity(0.8))
            .font(.custom("Georgia", size: 14))
    }
}

struct myStyleFrench: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding(10)
            .foregroundStyle(.pink.opacity(0.8))
            .font(.custom("Futura", size: 14))

            // πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘ Swift does not allow this πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘
            @State private var overTextgeneral = false
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(overTextgeneral ? .purple.opacity(0.8) : .white.opacity(0.1))
            )
            .onHover { over in overTextgeneral = over }
            // πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘ Swift does not allow this πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘πŸ›‘ 
    }
}

struct ContentView: View {

    var body: some View {

        VStack(spacing: 10) {
            Text("πŸ—£οΈ LET'S LEARN FRENCH ! πŸ—£οΈ")
                .modifier(myStyleEnglish())
            HStack(spacing: 10) {
                Text("CALL THE FIRE DEPARTMENT !")
                    .modifier(myStyleEnglish())
                Text("APPELEZ LES POMPIERS !")
                    .modifier(myStyleFrench())
            }

            HStack(spacing: 10) {
                Text("CALL THE AMBULANCE !")
                    .modifier(myStyleEnglish())
                Text("APPELER L'AMBULANCE !")
                    .modifier(myStyleFrench())
            }

            HStack(spacing: 10) {
                Text("CALL THE POLICE !")
                    .modifier(myStyleEnglish())
                Text("APPELEZ LA POLICE !")
                    .modifier(myStyleFrench())
            }

            HStack(spacing: 10) {
                Text("CALL CARETAKER !")
                    .modifier(myStyleEnglish())
                Text("APPELEZ LE GARDIEN !")
                    .modifier(myStyleFrench())
            }
            // Many more HStacks 😰
        }
    }
}

#Preview {
    ContentView()
}

Maybe the issue is that this .onHover method uses separate @State variables for separate implementations? Is there a way to apply the .onHover modifer to multiple Text views - for example inside a ViewModifier - so multiiple Text views have the same behaviour , but each will operate individually ( each has its .overlay independently turn purple on mouse hover ) ?

Thank you.

3      

Hi,

You just need to add the @State var outside the body:

struct myStyleFrench: ViewModifier {
    @State private var overText = false

    func body(content: Content) -> some View {
        content
            .padding(10)
            .foregroundStyle(.pink.opacity(0.8))
            .font(.custom("Futura", size: 14))
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(overText ? .purple.opacity(0.8) : .white.opacity(0.1))
            )
            .onHover { over in overText = over }
    }
}

4      

@Hectorcrdna Perfetct, thanks.

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.