iosswiftiphoneswiftuiuikit

How to apply inner shadow on SF symbols to make them look like as shown in the picture?


I have been trying to get this debossed effect in SwiftUI but nothing is working out. I tried shadow(color:radius:x:y:) modifier but it applies shadow on the outside of symbol. Can you please tell me if there are any other APIs or tricks to achieve this ? Thank You !

reference image


Solution

  • Love the debossed effect, reminds me of iOS 6. The key was finding inverseMask and then I had a play around and came up with this:

    enter image description here

    import SwiftUI
    
    extension View {
        // https://www.raywenderlich.com/7589178-how-to-create-a-neumorphic-design-with-swiftui
        func inverseMask<Mask>(_ mask: Mask) -> some View where Mask: View {
            self.mask(mask
                .foregroundColor(.black)
                .background(Color.white)
                .compositingGroup()
                .luminanceToAlpha()
            )
        }
    }
    
    struct DebossTest: View {
        static var lightPurple = UIColor(red: 212/255, green: 206/255, blue: 247/255, alpha: 1)
        
        var body: some View {
            ZStack {
                Color(uiColor: DebossTest.lightPurple)
                MyButton()
                    .font(.system(size: 144))
            }
        }
    }
    
    
    struct MyButton: View {
        
        static var darkPurple = UIColor(red: 140/255, green: 134/255, blue: 211/255, alpha: 1)
        let trashName = "trash.fill"
        
        var body: some View {
            ZStack {
                
                // the darker inset image
                Image(systemName: trashName)
                    .foregroundColor(Color(uiColor: MyButton.darkPurple))
                
                // black inner shadow
                Rectangle()
                    .inverseMask(Image(systemName: trashName))
                    .shadow(color: Color.black, radius: 1, x: 0, y: 1)
                    .mask(Image(systemName: trashName))
                    .clipped()
                
                // white bottom edges
                Image(systemName: trashName)
                    .shadow(color: Color.white, radius: 1, x: 0, y: 1)
                    .inverseMask(Image(systemName: trashName))
            }
            .frame(width: 185, height: 140)
        }
    }
    
    struct DebossTest_Previews: PreviewProvider {
        static var previews: some View {
            DebossTest()
        }
    }