SwiftUI এ ক্রিয়াকলাপ সূচক


97

SwiftUI এ একটি সম্পূর্ণ স্ক্রিন ক্রিয়াকলাপ সূচক যুক্ত করার চেষ্টা করা হচ্ছে।

আমি প্রোটোকলে .overlay(overlay: )ফাংশন ব্যবহার করতে পারি View

এটির সাহায্যে আমি যে কোনও ভিউ ওভারলে করতে পারি, তবে আমি iOS ডিফল্ট স্টাইলের UIActivityIndicatorViewসমতুল্য খুঁজে পাই না SwiftUI

আমি কীভাবে একটি ডিফল্ট স্টাইল স্পিনার তৈরি করতে পারি SwiftUI?

দ্রষ্টব্য: এটি ইউআইকিট কাঠামোর ক্রিয়াকলাপ সূচক যুক্ত করার বিষয়ে নয়।


আমি এটিও সন্ধান করার চেষ্টা করেছি, এবং ব্যর্থ হয়েছিলাম, অনুমান করি এটি পরে যুক্ত হবে :)
মার্কিসেভিক

প্রতিক্রিয়া সহকারী ব্যবহার করে অ্যাপলের সাথে একটি প্রতিক্রিয়া ইস্যু ফাইল করা নিশ্চিত করুন। বিটা প্রক্রিয়া চলাকালীন সময়ে অনুরোধগুলি পাওয়া আপনি ফ্রেমওয়ার্কে কী চান তা দেখার সেরা উপায়।
জন শিয়ের

উত্তর:


223

এর মতো Xcode 12 বিটা ( আইওএস 14 ), নামক একটি নতুন দৃশ্য ProgressViewহয় বিকাশকারীদের জন্য উপলব্ধ , এবং যে উভয় নির্ধারিত এবং অনির্দিষ্ট উন্নতি প্রদর্শন করতে পারেন।

এর স্টাইলটি ডিফল্ট হয় CircularProgressViewStyle, যা আমরা ঠিক খুঁজছি।

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

এক্সকোড 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)
            }
        }
    }

}

ফলাফল:

এখানে চিত্র বর্ণনা লিখুন


4
তবে কীভাবে এটি বন্ধ করা যায়?
বাগসফ্লায়ার

4
হাই @ মাত্তোপাচিনী, আপনার উত্তরের জন্য ধন্যবাদ তবে, আপনি কীভাবে আমাকে ক্রিয়াকলাপের সূচকটি আড়াল করতে পারেন দয়া করে আমাকে সহায়তা করতে পারেন। আপনি কি দয়া করে এর জন্য কোডটি লিখতে পারেন?
আনু

4
@ আলফি তার কোডে এটি বলেছে isShowing: .constant(true)। তার মানে সূচক সর্বদা প্রদর্শিত হয়। আপনার যা করা দরকার তা @Stateভেরিয়েবলের সাথে সত্য যা আপনি যখন লোডিং ইন্ডিকেটরটি প্রদর্শিত হতে চান (যখন ডেটা লোড হচ্ছে) এবং তারপরে এটি মিথ্যাতে পরিবর্তন করুন যখন আপনি লোডিং ইন্ডিকেটরটি অদৃশ্য হয়ে যেতে চান (যখন ডেটা লোড হয়ে গেলে) । যদি ভেরিয়েবলটিকে isDataLoadingউদাহরণস্বরূপ বলা হয় , আপনি isShowing: $isDataLoadingমাত্তিও যেখানে রেখেছিলেন তার পরিবর্তে আপনি তা করতে পারেন isShowing: .constant(true)
আরপিটেল 99

4
অ্যাক্টিভিটিস ইন্ডিকেটরের ভিতরে বা লোডিংভিউতে এটি পরিবর্তন করা হচ্ছে না বলে @ মাত্তোপাচিনি আপনার আসলে এটির জন্য একটি বাঁধার প্রয়োজন হয় না। কেবল একটি নিয়মিত বুলিয়ান পরিবর্তনশীল কাজ করে। বাইন্ডিংটি যখন আপনি ভিউর ভিতরে ভেরিয়েবলটি পরিবর্তন করতে চান এবং সেই পরিবর্তনটি পিতামাতার কাছে ফেরত দিতে চান তখন তার জন্য দরকারী B
হেলাম

4
@nelsonPARRILLA আমার সন্দেহ হয় যে tintColorকেবল খাঁটি সুইফট ইউআই ভিউতে কাজ করে - ব্রিজড ( 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)

এখানে চিত্র বর্ণনা লিখুন


এটি আমাকে অনেক সাহায্য করেছে, অনেক ধন্যবাদ! আপনি চেনাশোনাগুলি তৈরি করতে ফাংশনগুলি সংজ্ঞায়িত করতে এবং এনিমেশনগুলিকে আরও পঠনযোগ্য করার জন্য ভিউ সংশোধক যুক্ত করতে পারেন।
আরিফ আতা কেনজিজ

4
এই সমাধান ভালবাসা!
জন ভোগেল

4
যদি অ্যানিমেশনটি একটি রাজ্য হয় তবে আমি কীভাবে অ্যানিমেশনটি সরিয়ে দেব?
ডি নিড

44

আইওএস 14 - স্থানীয়

এটি কেবল একটি সাধারণ দৃষ্টিভঙ্গি।

ProgressView()

বর্তমানে এটি ডিফল্ট হয়েছে CircularProgressViewStyleতবে আপনি নিম্নলিখিত মোডিফার যুক্ত করে ম্যানুয়ালি এটির স্টাইল সেট করতে পারেন:

.progressViewStyle(CircularProgressViewStyle())

এছাড়াও, শৈলীটি যে কোনও কিছু হতে পারে ProgressViewStyle


আইওএস 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)
    }
}

Ones হাড়ের সম্প্রসারণ:

এই সামান্য সহায়ক এক্সটেনশনের সাহায্যে আপনি 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
}

এই পদ্ধতিটি পুরোপুরি অভিযোজিত। উদাহরণ হিসেবে বলা যায়, আপনি দেখতে পারেন কিভাবে পাঠ্যক্ষেত্র প্রথম উত্তর প্রদানকারী পরিণত করতে একই পদ্ধতি সঙ্গে এখানে


প্রগ্রেভিউয়ের রঙ কীভাবে পরিবর্তন করবেন?
বাগসফ্লিয়ার

.progressViewStyle(CircularProgressViewStyle(tint: Color.red))রঙ পরিবর্তন করবে
বাগসফ্লায়ার

আপনার "বোনাস এক্সটেনশান: কনফিগার ()" দ্বিতীয় বারের জন্য মেমরি গ্রহণ করে আরম্ভ করুন। আমি কি সঠিক? বা এটি কি এতটাই অপ্টিমাইজড যে আমাদের এই জাতীয় শৃঙ্খলা বিন্যাস করার অনুমতি দেওয়া হয়েছে?
রুজার্ড

এটি একটি চিনি, এটি এই ক্ষেত্রে খুব ব্যয়বহুল নয় তবে আমি বড় দর্শনগুলির জন্য পারফরম্যান্সের হিটটি পরিমাপ করি নি। আপনি বাস্তবায়নটি আরও দক্ষ কিছুতে পরিমাপ করতে এবং পরিবর্তন করতে পারেন (যেহেতু এটি একটি শ্রেণি) তবে স্ট্রাক্টের সূচনা করা চিন্তিত হওয়া এতটা ব্যয়বহুল নয়
মোজতাবা হোসেইনি

8

কাস্টম সূচক

যদিও অ্যাপল এখনই সুইফটইউআই ২.০ থেকে নেটিভ অ্যাক্টিভিটি সূচককে সমর্থন করে, আপনি কেবল নিজের অ্যানিমেশনগুলি প্রয়োগ করতে পারেন। এগুলি সবই সুইফটুআই 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যে আবশ্যক টগল চালানো হবে।


এটা অসাধারণ! যদিও আমি একটি বাগ পেয়েছি - এর জন্য সত্যিই অদ্ভুত একটি অ্যানিমেশন রয়েছেiActivityIndicator(style: .rotatingShapes(count: 10, size: 15))
পাভেলো 2222

iActivityIndicator().style(.rotatingShapes(count: 10, size: 15))উপায় দ্বারা সমস্যা কি ? @ পাওলো 2222?
মোজতাবা হোসেইনি

আপনি যদি count5 বা তার চেয়ে কম সেট করেন তবে অ্যানিমেশনটি দেখতে দুর্দান্ত ( এই উত্তরের সাথে মিল রয়েছে )। তবে আপনি যদি count15 এ সেট করেন তবে শীর্ষস্থানীয় বিন্দুটি বৃত্তের শীর্ষে থামবে না । এটি অন্য চক্র করা শুরু করে, তারপরে ফিরে আসে এবং তারপরে আবার চক্রটি শুরু হয়। আমি এটা নিশ্চিত কিনা নিশ্চিত। কেবলমাত্র সিমুলেটারে পরীক্ষিত, এক্সকোড 12.0.1।
পাভেলো 2222

হুমমমম। কারণ অ্যানিমেশনগুলি সিরিয়ালযুক্ত নয়। এর জন্য ফ্রেমওয়ার্কটিতে আমার ক্রমিক বিকল্প যুক্ত করা উচিত। আপনার মতামত ভাগ করার জন্য ধন্যবাদ।
মোজতাবা হোসেইনি

@ মজতাবা হুসেইনি আপনি কীভাবে দৌড়ানোর বাঁধাই টগল করেন?
গ্যারিসাবো

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

মোজতবা হোসেইনির উত্তর ছাড়াও ,

আমি কয়েকটি আপডেট করেছি যাতে এটি একটি সুইফ্ট প্যাকেজে রাখা যায় :

ক্রিয়াকলাপ সূচক:

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

SwiftUI এ ক্রিয়াকলাপ সূচক


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

SwiftUI এ ক্রিয়াকলাপ সূচক



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

এখানে চিত্র বর্ণনা লিখুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.