# निरंतर पल्स (लूप) कैसे बनाएँ

> LoopAnimation के साथ किसी वैल्यू को अनंत चक्र में एनिमेट करें, जो लोडिंग संकेतकों और ग्लो इफ़ेक्ट के लिए उपयोगी है।

Source: https://crossfly.dev/hi/docs/cookbook/anim/pulso-loop — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# निरंतर पल्स (लूप) कैसे बनाएँ

**उद्देश्य.** किसी चीज़ को अनिश्चित काल तक पल्स/ब्लिंक कराना ("लोडिंग" संकेतक, ग्लो, किसी बटन की श्वास)। `LoopAnimation` किसी वैल्यू को बार-बार 0 → 1 चक्र में घुमाता है, easing के साथ या बिना, **बिना** `onComplete` (यह अनंत है — आप इसे `stop()` से रोकते हैं)।

## उपयोग किए गए APIs
- `new LoopAnimation(float duration [, float fps, boolean easeInOut])` — प्रत्येक चक्र `duration` सेकंड तक चलता है और स्वयं पुनः आरंभ होता है। `fps` डिफ़ॉल्ट 60; `easeInOut` डिफ़ॉल्ट `false` (linear)। `easeInOut=true` के साथ, प्रति चक्र ease-in-out cubic लागू करता है।
- `LoopAnimation.onUpdate(Runnable)` — प्रत्येक फ्रेम पर callback; `getValue()` (0–1, वर्तमान चक्र की प्रगति) पढ़ें।
- `LoopAnimation.getValue()` — चक्र की वर्तमान प्रगति।
- `LoopAnimation.start()` / `stop()` — लूप आरंभ / रोकता है। **न `onComplete` है और न `cancel()`** — यह स्वभाव से अनंत है।
- `Component.alpha(float)` — ओपेसिटी लागू करता है ("श्वास" इफ़ेक्ट के लिए)।
- `Component.repaint()` — स्टैटिक; `onUpdate` में अनिवार्य।

## पूरा उदाहरण (कॉपी करें, पेस्ट करें और चलाएँ)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.animation.*;

/** चलाने योग्य मुख्य स्क्रीन: एक "●" को loop में स्पंदित करती है; स्क्रीन बंद होने पर loop रोकें। */
public class MainWindow extends Window
{
   private LoopAnimation pulse;

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label dot = new Label("●");
      add(dot);

      // 1 s चक्र, 60 fps, easing के साथ (कोमल स्पंदन)
      pulse = new LoopAnimation(1f, 60f, true);
      pulse.onUpdate(() ->
         {
            // मान 0 → 1 जाता है और पुनः आरंभ होता है; अपारदर्शिता 0.3 → 1.0 में मैप होता है
            float v = 0.3f + 0.7f * pulse.getValue();
            dot.alpha(v);
            Component.repaint();
         })
         .start();

      // बटन जो स्पंदन समाप्त करता है (उदा.: जब लोडिंग समाप्त हो)
      add(new Button("Parar").onAction(e -> pulse.stop()));
   }

   @Override
   public void onRemove()
   {
      // स्क्रीन से बाहर निकलते समय रोकें ताकि कोई अनाथ loop स्क्रीन के बाहर एनिमेट न होता रहे।
      if (pulse != null) pulse.stop();
      super.onRemove();
   }
}
```

> नीचे दिया गया अंश **केवल मुख्य भाग** दिखाता है। इसे चलाने के लिए, इसे ऊपर दिए गए `MainWindow` कंकाल में रखें।

## न्यूनतम अंश
```java
// स्रोत में सत्यापित: LoopAnimation(duration, fps, easeInOut); कोई onComplete नहीं; stop() से रोकें
Label dot = new Label("●");
add(dot);

// 1 s चक्र, 60 fps, easing के साथ (कोमल स्पंदन)
LoopAnimation pulse = new LoopAnimation(1f, 60f, true);
pulse.onUpdate(() ->
   {
      // मान 0 → 1 जाता है और पुनः आरंभ होता है; अपारदर्शिता 0.3 → 1.0 में मैप होता है
      float v = 0.3f + 0.7f * pulse.getValue();
      dot.alpha(v);
      Component.repaint();
   })
   .start();

// बाद में, स्पंदन समाप्त करने के लिए (उदा.: जब लोडिंग समाप्त हो):
pulse.stop();
```

महत्वपूर्ण सावधानियाँ:

- **संदर्भ सुरक्षित रखें** (`pulse`) ताकि आप `stop()` कॉल कर सकें। बिना `stop()` वाला एक `LoopAnimation` हमेशा चलता रहता है और लगातार CPU/GPU खपत करता है (प्रत्येक फ्रेम `repaint()` कॉल करता है)।
- **स्क्रीन छोड़ते समय रोकें**: जब `Window` बंद हो (`onRemove`/`hide`) तब `pulse.stop()` कॉल करें ताकि स्क्रीन के बाहर एनिमेट होता एक अनाथ लूप न रह जाए।
- `getValue()` प्रत्येक चक्र के आरंभ में 0 पर लौटता है। "आगे-और-वापस" पल्स (0→1→0) के लिए, `getValue()` पर एक त्रिकोणीय या साइन फ़ंक्शन के साथ मैप करें।

## और गहराई से जानें
- [वैल्यू एनिमेशन](/docs/ui/animations/value-animations) · [Press और फ़ीडबैक](/docs/ui/animations/press-and-feedback)
- संबंधित रेसिपी: [किसी कंपोनेंट का Fade](/docs/cookbook/anim/fade) · [किसी कंपोनेंट को हिलाना](/docs/cookbook/anim/mover-componente)
