स्विफ्टयूआई में गतिविधि सूचक


97

SwiftUI में एक पूर्ण स्क्रीन गतिविधि संकेतक जोड़ने की कोशिश कर रहा है।

मैं प्रोटोकॉल .overlay(overlay: )में फ़ंक्शन का उपयोग कर सकता हूं View

इसके साथ, मैं किसी भी दृश्य को ओवरले कर सकता हूं, लेकिन मुझे iOS डिफ़ॉल्ट शैली के UIActivityIndicatorViewबराबर नहीं मिल सकता है SwiftUI

मैं एक डिफ़ॉल्ट स्टाइल स्पिनर कैसे बना सकता हूं SwiftUI?

नोट: यह UIKit ढांचे में गतिविधि संकेतक जोड़ने के बारे में नहीं है।


मैंने इसे भी खोजने की कोशिश की, और असफल रहा, लगता है कि इसे बाद में जोड़ा जाएगा :)
Markicevic

फ़ीडबैक सहायक का उपयोग करके Apple के साथ प्रतिक्रिया समस्या दर्ज करना सुनिश्चित करें। बीटा प्रक्रिया के दौरान जल्दी से अनुरोध प्राप्त करना यह देखने का सबसे अच्छा तरीका है कि आप ढांचे में क्या चाहते हैं।
जॉन शियर

जवाबों:


223

के रूप में Xcode 12 बीटा ( आईओएस 14 ) कहा जाता है, कोई नया दृश्य ProgressViewहै डेवलपर्स के लिए उपलब्ध है, और है कि दोनों नियत और अनिश्चित प्रगति प्रदर्शित कर सकते हैं।

इसकी शैली को डिफॉल्ट करता है CircularProgressViewStyle, जो कि वास्तव में हम देख रहे हैं।

var body: some View {
    VStack {
        ProgressView()
           // and if you want to be explicit / future-proof...
           // .progressViewStyle(CircularProgressViewStyle())
    }
}

Xcode 11.x

काफी कुछ विचारों को अभी तक प्रतिनिधित्व नहीं किया गया है SwiftUI, लेकिन उन्हें आसानी से सिस्टम में पोर्ट करना है। आपको UIActivityIndicatorइसे लपेटने और बनाने की आवश्यकता है UIViewRepresentable

(इसके बारे में और अधिक जानकारी डब्ल्यूडब्ल्यूडीसी 2019 की बातचीत में मिल सकती है - एकीकृत स्विफ्टयूआई )

struct ActivityIndicator: UIViewRepresentable {

    @Binding var isAnimating: Bool
    let style: UIActivityIndicatorView.Style

    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: style)
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
    }
}

फिर आप इसे निम्नानुसार उपयोग कर सकते हैं - यहां एक लोडिंग ओवरले का एक उदाहरण है।

नोट: मैं उपयोग करना पसंद करता हूं ZStack, बजाय overlay(:_), इसलिए मुझे पता है कि वास्तव में मेरे कार्यान्वयन में क्या हो रहा है।

struct LoadingView<Content>: View where Content: View {

    @Binding var isShowing: Bool
    var content: () -> Content

    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .center) {

                self.content()
                    .disabled(self.isShowing)
                    .blur(radius: self.isShowing ? 3 : 0)

                VStack {
                    Text("Loading...")
                    ActivityIndicator(isAnimating: .constant(true), style: .large)
                }
                .frame(width: geometry.size.width / 2,
                       height: geometry.size.height / 5)
                .background(Color.secondary.colorInvert())
                .foregroundColor(Color.primary)
                .cornerRadius(20)
                .opacity(self.isShowing ? 1 : 0)

            }
        }
    }

}

इसका परीक्षण करने के लिए, आप इस उदाहरण कोड का उपयोग कर सकते हैं:

struct ContentView: View {

    var body: some View {
        LoadingView(isShowing: .constant(true)) {
            NavigationView {
                List(["1", "2", "3", "4", "5"], id: \.self) { row in
                    Text(row)
                }.navigationBarTitle(Text("A List"), displayMode: .large)
            }
        }
    }

}

परिणाम:

यहाँ छवि विवरण दर्ज करें


1
लेकिन इसे कैसे रोका जाए?
Bagusflyer

1
हाय @MatteoPacini, आपके उत्तर के लिए धन्यवाद। लेकिन, क्या आप कृपया मेरी मदद कर सकते हैं कि मैं गतिविधि संकेतक को कैसे छिपा सकता हूं। क्या आप इसके लिए कोड डाल सकते हैं?
अन्नू

4
@ अपने कोड में इसे कहते हैं isShowing: .constant(true)। इसका मतलब है कि संकेतक हमेशा दिखा रहा है। आपको जो करने की आवश्यकता है वह एक @Stateचर है जो सच है जब आप चाहते हैं कि लोडिंग इंडिकेटर दिखाई दे (जब डेटा लोड हो रहा है), और फिर तब बदल दें जब आप चाहते हैं कि लोडिंग इंडिकेटर गायब हो जाए (जब डेटा लोड हो रहा है) । यदि चर को isDataLoadingउदाहरण के लिए कहा जाता है, तो आप isShowing: $isDataLoadingइसके बजाय जहां माटेओ डालते हैं , वह करेंगे isShowing: .constant(true)
RPatel99

1
@MatteoPacini आपको वास्तव में इसके लिए किसी बाइंडिंग की आवश्यकता नहीं है क्योंकि यह ActivIndicator के अंदर या LoadingView में संशोधित नहीं किया जा रहा है। बस एक नियमित बूलियन चर काम करता है। जब आप दृश्य के अंदर चर को संशोधित करना चाहते हैं और उस परिवर्तन को वापस जनक को भेजना चाहते हैं, तो बाइंडिंग उपयोगी है।
हेलम

1
@nelsonPARRILLA मुझे संदेह है कि tintColorकेवल शुद्ध स्विफ्ट UI विचारों पर काम करता है - ब्रिजेड ( UIViewRepresentable) वाले पर नहीं ।
मत्तेओ पैकिनी

51

यदि आप एक स्विफ्ट-यू-स्टाइल समाधान चाहते हैं, तो यह जादू है:

import SwiftUI

struct ActivityIndicator: View {

  @State private var isAnimating: Bool = false

  var body: some View {
    GeometryReader { (geometry: GeometryProxy) in
      ForEach(0..<5) { index in
        Group {
          Circle()
            .frame(width: geometry.size.width / 5, height: geometry.size.height / 5)
            .scaleEffect(!self.isAnimating ? 1 - CGFloat(index) / 5 : 0.2 + CGFloat(index) / 5)
            .offset(y: geometry.size.width / 10 - geometry.size.height / 2)
          }.frame(width: geometry.size.width, height: geometry.size.height)
            .rotationEffect(!self.isAnimating ? .degrees(0) : .degrees(360))
            .animation(Animation
              .timingCurve(0.5, 0.15 + Double(index) / 5, 0.25, 1, duration: 1.5)
              .repeatForever(autoreverses: false))
        }
      }
    .aspectRatio(1, contentMode: .fit)
    .onAppear {
        self.isAnimating = true
    }
  }
}

बस उपयोग करने के लिए:

ActivityIndicator()
.frame(width: 50, height: 50)

आशा है कि इससे सहायता मिलेगी!

उदाहरण उपयोग:

ActivityIndicator()
.frame(size: CGSize(width: 200, height: 200))
    .foregroundColor(.orange)

यहाँ छवि विवरण दर्ज करें


इससे मुझे बहुत मदद मिली, बहुत बहुत धन्यवाद! आप मंडलियों को बनाने और उन्हें अधिक पठनीय बनाने के लिए एनिमेशन के लिए व्यू संशोधक जोड़ने के लिए फ़ंक्शंस परिभाषित कर सकते हैं।
आरिफ़ अता केंगिज़

2
इस समाधान से प्यार करें!
जॉन वोगेल

1
मैं एनीमेशन को कैसे हटाऊंगा यदि isAimimating एक राज्य है, इसके बजाय @Binding हो सकता है?
डि नर्ड

44

iOS 14 - नेटिव

यह सिर्फ एक साधारण दृश्य है।

ProgressView()

वर्तमान में, यह डिफ़ॉल्ट रूप से है, CircularProgressViewStyleलेकिन आप निम्न मॉडिफायर जोड़कर इसकी शैली को मैन्युअल रूप से सेट कर सकते हैं:

.progressViewStyle(CircularProgressViewStyle())

इसके अलावा, शैली कुछ भी हो सकती है जो इसके अनुरूप हो ProgressViewStyle


iOS 13 - UIActivityIndicatorस्विफ्टयूआई में पूरी तरह से अनुकूलन योग्य मानक : (बिल्कुल मूल के रूप में View):

आप इसे बना सकते हैं और इसे कॉन्फ़िगर कर सकते हैं (जितना आप मूल में कर सकते हैं UIKit):

ActivityIndicator(isAnimating: loading)
    .configure { $0.color = .yellow } // Optional configurations (🎁 bones)
    .background(Color.blue)

परिणाम


बस इस आधार को लागू करें structऔर आप जाने के लिए अच्छा होगा:

struct ActivityIndicator: UIViewRepresentable {
    
    typealias UIView = UIActivityIndicatorView
    var isAnimating: Bool
    fileprivate var configuration = { (indicator: UIView) in }

    func makeUIView(context: UIViewRepresentableContext<Self>) -> UIView { UIView() }
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<Self>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
        configuration(uiView)
    }
}

Extension हड्डियों का विस्तार:

इस छोटे से उपयोगी विस्तार के साथ, आप modifierअन्य स्विफ्टयूआई की तरह विन्यास का उपयोग कर सकते हैं view:

extension View where Self == ActivityIndicator {
    func configure(_ configuration: @escaping (Self.UIView)->Void) -> Self {
        Self.init(isAnimating: self.isAnimating, configuration: configuration)
    }
}

क्लासिक तरीका:

इसके अलावा, आप एक क्लासिक इनिशलाइज़र में दृश्य को कॉन्फ़िगर कर सकते हैं:

ActivityIndicator(isAnimating: loading) { 
    $0.color = .red
    $0.hidesWhenStopped = false
    //Any other UIActivityIndicatorView property you like
}

यह विधि पूरी तरह से अनुकूलनीय है। उदाहरण के लिए, आप देख सकते हैं कि कैसे TextField बनाने के लिए यहां एक ही विधि के साथ पहला उत्तरदाता बनें


ProgressView का रंग कैसे बदलें?
Bagusflyer

.progressViewStyle(CircularProgressViewStyle(tint: Color.red))रंग बदलेगा
Bagusflyer

आपका "बोनस एक्सटेंशन: कॉन्फ़िगर ()" दूसरी बार कॉल करता है, मेमोरी ले रहा है। क्या मैं सही हू? या क्या यह इतना अधिक अनुकूलित है कि हमें इस तरह के चेन इनविटेशन करने की अनुमति है?
रुज़ार्ड

यह एक चीनी है, यह इस मामले के लिए बहुत महंगा नहीं है, लेकिन मैंने बड़े विचारों के लिए प्रदर्शन हिट को नहीं मापा। आप कार्यान्वयन को कुछ और अधिक कुशल (क्योंकि यह एक वर्ग है) को माप सकते हैं और बदल सकते हैं, लेकिन एक संरचना को शुरू करना इतना महंगा नहीं है कि इसके बारे में चिंतित हों
Mojtaba Hosseini

8

कस्टम संकेतक

हालाँकि Apple अब SwiftUI 2.0 से देशी गतिविधि संकेतक का समर्थन करता है, आप बस अपने स्वयं के एनिमेशन को लागू कर सकते हैं। ये सभी SwiftUI 1.0 पर समर्थित हैं। इसके अलावा यह है विजेट में काम कर रहे।

आर्क्स

struct Arcs: View {
    @Binding var isAnimating: Bool
    let count: UInt
    let width: CGFloat
    let spacing: CGFloat

    var body: some View {
        GeometryReader { geometry in
            ForEach(0..<Int(count)) { index in
                item(forIndex: index, in: geometry.size)
                    .rotationEffect(isAnimating ? .degrees(360) : .degrees(0))
                    .animation(
                        Animation.default
                            .speed(Double.random(in: 0.2...0.5))
                            .repeatCount(isAnimating ? .max : 1, autoreverses: false)
                    )
            }
        }
        .aspectRatio(contentMode: .fit)
    }

    private func item(forIndex index: Int, in geometrySize: CGSize) -> some View {
        Group { () -> Path in
            var p = Path()
            p.addArc(center: CGPoint(x: geometrySize.width/2, y: geometrySize.height/2),
                     radius: geometrySize.width/2 - width/2 - CGFloat(index) * (width + spacing),
                     startAngle: .degrees(0),
                     endAngle: .degrees(Double(Int.random(in: 120...300))),
                     clockwise: true)
            return p.strokedPath(.init(lineWidth: width))
        }
        .frame(width: geometrySize.width, height: geometrySize.height)
    }
}

विभिन्न रूपों का डेमो आर्क्स


सलाखों

struct Bars: View {
    @Binding var isAnimating: Bool
    let count: UInt
    let spacing: CGFloat
    let cornerRadius: CGFloat
    let scaleRange: ClosedRange<Double>
    let opacityRange: ClosedRange<Double>

    var body: some View {
        GeometryReader { geometry in
            ForEach(0..<Int(count)) { index in
                item(forIndex: index, in: geometry.size)
            }
        }
        .aspectRatio(contentMode: .fit)
    }

    private var scale: CGFloat { CGFloat(isAnimating ? scaleRange.lowerBound : scaleRange.upperBound) }
    private var opacity: Double { isAnimating ? opacityRange.lowerBound : opacityRange.upperBound }

    private func size(count: UInt, geometry: CGSize) -> CGFloat {
        (geometry.width/CGFloat(count)) - (spacing-2)
    }

    private func item(forIndex index: Int, in geometrySize: CGSize) -> some View {
        RoundedRectangle(cornerRadius: cornerRadius,  style: .continuous)
            .frame(width: size(count: count, geometry: geometrySize), height: geometrySize.height)
            .scaleEffect(x: 1, y: scale, anchor: .center)
            .opacity(opacity)
            .animation(
                Animation
                    .default
                    .repeatCount(isAnimating ? .max : 1, autoreverses: true)
                    .delay(Double(index) / Double(count) / 2)
            )
            .offset(x: CGFloat(index) * (size(count: count, geometry: geometrySize) + spacing))
    }
}

विभिन्न रूपों का डेमो सलाखों


ऐनक

struct Blinking: View {
    @Binding var isAnimating: Bool
    let count: UInt
    let size: CGFloat

    var body: some View {
        GeometryReader { geometry in
            ForEach(0..<Int(count)) { index in
                item(forIndex: index, in: geometry.size)
                    .frame(width: geometry.size.width, height: geometry.size.height)

            }
        }
        .aspectRatio(contentMode: .fit)
    }

    private func item(forIndex index: Int, in geometrySize: CGSize) -> some View {
        let angle = 2 * CGFloat.pi / CGFloat(count) * CGFloat(index)
        let x = (geometrySize.width/2 - size/2) * cos(angle)
        let y = (geometrySize.height/2 - size/2) * sin(angle)
        return Circle()
            .frame(width: size, height: size)
            .scaleEffect(isAnimating ? 0.5 : 1)
            .opacity(isAnimating ? 0.25 : 1)
            .animation(
                Animation
                    .default
                    .repeatCount(isAnimating ? .max : 1, autoreverses: true)
                    .delay(Double(index) / Double(count) / 2)
            )
            .offset(x: x, y: y)
    }
}

विभिन्न रूपों का डेमो ऐनक


कोड की दीवारों को रोकने के लिए , आप गिट पर आयोजित इस रेपो में अधिक सुरुचिपूर्ण संकेतक पा सकते हैं ।

ध्यान दें कि इन सभी एनिमेशन एक है Bindingकि MUST टॉगल चलाने के लिए।


यह भी खूब रही! मैं एक बग हालांकि पाया है - वहाँ के लिए एक बहुत ही अजीब एनीमेशन हैiActivityIndicator(style: .rotatingShapes(count: 10, size: 15))
pawello2222

iActivityIndicator().style(.rotatingShapes(count: 10, size: 15))जिस तरह से साथ मुद्दा है ? @ pawello2222?
मोजतबा होसैनी

यदि आप count5 या उससे कम सेट करते हैं , तो एनीमेशन ठीक दिखता है ( इस उत्तर के समान दिखता है )। हालाँकि, यदि आप count15 को सेट करते हैं , तो प्रमुख डॉट सर्कल के शीर्ष पर नहीं रुकता है । यह दूसरा चक्र करना शुरू करता है, फिर शीर्ष पर वापस आता है और फिर चक्र शुरू करता है। मुझे यकीन नहीं है अगर यह इरादा है। केवल सिम्युलेटर पर परीक्षण, Xcode 12.0.1।
पावेलो 2222

Hmmmm। ऐसा इसलिए है क्योंकि एनिमेशन क्रमबद्ध नहीं हैं। मुझे उस के लिए रूपरेखा में क्रमबद्ध विकल्प जोड़ना चाहिए। राय बताने के लिए आपका धन्यवाद।
मोजतबा होसैनी

@MojtabaHosseini आप दौड़ने के लिए बंधन को कैसे टॉगल करती हैं?
गैरीसाबो

4

मैंने स्विफ्टयूआई का उपयोग करके क्लासिक यूइकिट संकेतक को लागू किया। यहां क्रिया में गतिविधि संकेतक देखें

struct ActivityIndicator: View {
  @State private var currentIndex: Int = 0

  func incrementIndex() {
    currentIndex += 1
    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(50), execute: {
      self.incrementIndex()
    })
  }

  var body: some View {
    GeometryReader { (geometry: GeometryProxy) in
      ForEach(0..<12) { index in
        Group {
          Rectangle()
            .cornerRadius(geometry.size.width / 5)
            .frame(width: geometry.size.width / 8, height: geometry.size.height / 3)
            .offset(y: geometry.size.width / 2.25)
            .rotationEffect(.degrees(Double(-360 * index / 12)))
            .opacity(self.setOpacity(for: index))
        }.frame(width: geometry.size.width, height: geometry.size.height)
      }
    }
    .aspectRatio(1, contentMode: .fit)
    .onAppear {
      self.incrementIndex()
    }
  }

  func setOpacity(for index: Int) -> Double {
    let opacityOffset = Double((index + currentIndex - 1) % 11 ) / 12 * 0.9
    return 0.1 + opacityOffset
  }
}

struct ActivityIndicator_Previews: PreviewProvider {
  static var previews: some View {
    ActivityIndicator()
      .frame(width: 50, height: 50)
      .foregroundColor(.blue)
  }
}


3

के अलावा Mojatba होसेनी के जवाब ,

मैंने कुछ अपडेट किए हैं ताकि इसे एक स्विफ्ट पैकेज में रखा जा सके :

गतिविधि सूचक:

import Foundation
import SwiftUI
import UIKit

public struct ActivityIndicator: UIViewRepresentable {

  public typealias UIView = UIActivityIndicatorView
  public var isAnimating: Bool = true
  public var configuration = { (indicator: UIView) in }

 public init(isAnimating: Bool, configuration: ((UIView) -> Void)? = nil) {
    self.isAnimating = isAnimating
    if let configuration = configuration {
        self.configuration = configuration
    }
 }

 public func makeUIView(context: UIViewRepresentableContext<Self>) -> UIView {
    UIView()
 }

 public func updateUIView(_ uiView: UIView, context: 
    UIViewRepresentableContext<Self>) {
     isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
     configuration(uiView)
}}

एक्सटेंशन:

public extension View where Self == ActivityIndicator {
func configure(_ configuration: @escaping (Self.UIView) -> Void) -> Self {
    Self.init(isAnimating: self.isAnimating, configuration: configuration)
 }
}

2

स्विफ्टयूआई में गतिविधि सूचक


import SwiftUI

struct Indicator: View {

    @State var animateTrimPath = false
    @State var rotaeInfinity = false

    var body: some View {

        ZStack {
            Color.black
                .edgesIgnoringSafeArea(.all)
            ZStack {
                Path { path in
                    path.addLines([
                        .init(x: 2, y: 1),
                        .init(x: 1, y: 0),
                        .init(x: 0, y: 1),
                        .init(x: 1, y: 2),
                        .init(x: 3, y: 0),
                        .init(x: 4, y: 1),
                        .init(x: 3, y: 2),
                        .init(x: 2, y: 1)
                    ])
                }
                .trim(from: animateTrimPath ? 1/0.99 : 0, to: animateTrimPath ? 1/0.99 : 1)
                .scale(50, anchor: .topLeading)
                .stroke(Color.yellow, lineWidth: 20)
                .offset(x: 110, y: 350)
                .animation(Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true))
                .onAppear() {
                    self.animateTrimPath.toggle()
                }
            }
            .rotationEffect(.degrees(rotaeInfinity ? 0 : -360))
            .scaleEffect(0.3, anchor: .center)
            .animation(Animation.easeInOut(duration: 1.5)
            .repeatForever(autoreverses: false))
            .onAppear(){
                self.rotaeInfinity.toggle()
            }
        }
    }
}

struct Indicator_Previews: PreviewProvider {
    static var previews: some View {
        Indicator()
    }
}

स्विफ्टयूआई में गतिविधि सूचक



0
// Activity View

struct ActivityIndicator: UIViewRepresentable {

    let style: UIActivityIndicatorView.Style
    @Binding var animate: Bool

    private let spinner: UIActivityIndicatorView = {
        $0.hidesWhenStopped = true
        return $0
    }(UIActivityIndicatorView(style: .medium))

    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
        spinner.style = style
        return spinner
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
        animate ? uiView.startAnimating() : uiView.stopAnimating()
    }

    func configure(_ indicator: (UIActivityIndicatorView) -> Void) -> some View {
        indicator(spinner)
        return self
    }   
}

// Usage
struct ContentView: View {

    @State var animate = false

    var body: some View {
            ActivityIndicator(style: .large, animate: $animate)
                .configure {
                    $0.color = .red
            }
            .background(Color.blue)
    }
}


0
struct ContentView: View {
    
    @State private var isCircleRotating = true
    @State private var animateStart = false
    @State private var animateEnd = true
    
    var body: some View {
        
        ZStack {
            Circle()
                .stroke(lineWidth: 10)
                .fill(Color.init(red: 0.96, green: 0.96, blue: 0.96))
                .frame(width: 150, height: 150)
            
            Circle()
                .trim(from: animateStart ? 1/3 : 1/9, to: animateEnd ? 2/5 : 1)
                .stroke(lineWidth: 10)
                .rotationEffect(.degrees(isCircleRotating ? 360 : 0))
                .frame(width: 150, height: 150)
                .foregroundColor(Color.blue)
                .onAppear() {
                    withAnimation(Animation
                                    .linear(duration: 1)
                                    .repeatForever(autoreverses: false)) {
                        self.isCircleRotating.toggle()
                    }
                    withAnimation(Animation
                                    .linear(duration: 1)
                                    .delay(0.5)
                                    .repeatForever(autoreverses: true)) {
                        self.animateStart.toggle()
                    }
                    withAnimation(Animation
                                    .linear(duration: 1)
                                    .delay(1)
                                    .repeatForever(autoreverses: true)) {
                        self.animateEnd.toggle()
                    }
                }
        }
    }
}

यहाँ छवि विवरण दर्ज करें


0

यह स्विफ्टयूआई 2.0 के साथ वास्तव में आसान है मैंने इस सरल और आसान कस्टम दृश्य के साथ बनाया ProgressView

यहाँ है कि यह कैसा दिखता है: यहाँ

कोड:

import SwiftUI

struct ActivityIndicatorView: View {
    @Binding var isPresented:Bool
    var body: some View {
        if isPresented{
            ZStack{
                RoundedRectangle(cornerRadius: 15).fill(CustomColor.gray.opacity(0.1))
                ProgressView {
                    Text("Loading...")
                        .font(.title2)
                }
            }.frame(width: 120, height: 120, alignment: .center)
            .background(RoundedRectangle(cornerRadius: 25).stroke(CustomColor.gray,lineWidth: 2))
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.