इस पेज का अनुवाद मशीन द्वारा किया गया है और इसमें त्रुटियाँ हो सकती हैं। मूल अंग्रेज़ी पढ़ें

एलिमेंट

Scroll

Scroll एक नेटिव स्क्रोल व्यू है (iOS और Mac Catalyst पर UIScrollView, Android पर ScrollView)। यह अपने सभी चाइल्ड को अपने कंटेंट के रूप में लेआउट करता है और उन्हें नेटिव रूप से स्क्रोल करता है: स्क्रॉलिंग, फ्लिंगिंग, बाउंसिंग और स्नैपिंग प्लेटफ़ॉर्म पर, डिस्प्ले की रेट से चलती हैं। Rust में इसे scroll() से बनाया जाता है, TSX में nsh से <Scroll> के द्वारा।

el-scroll.tsx
el-scroll.tsxLive
import { mount, Scroll, type ScrollRef, signal, Text, View } from "nsh";
import { button, buttonText, desktop, Inspector, Panel, size, ui, wide } from "./palette";

// The page colors, read when they render: they follow the theme.
const colors = (): string[] => [ui().accent, ui().info, ui().violet, ui().down, ui().warn, ui().up];

function App() {
  const page = signal(0);
  // A page is as wide as the scroll view: 390 on a phone, wider on a desktop.
  const width = signal(390);
  const y = signal(0);
  let scroller!: ScrollRef;
  const rows = Array.from({ length: 40 }, (_, i) => i + 1);

  /** Pages as wide as the scroll view; `inset`: each page's margin. */
  const pager = (inset: number, style: object) => (
    <Scroll
      horizontal
      pagingEnabled
      scrollbar={false}
      style={style}
      onLayout={({ bounds }) => width.set(bounds.size.width)}
      onMomentumEnd={({ offset }) => page.set(Math.round(offset.x / width()))}
    >
      <Each of={colors()}>
        {(color, index) => (
          <View style={{ width: width(), padding: inset }}>
            <View style={{ flex: 1, borderRadius: 16, backgroundColor: color(), alignItems: "center", justifyContent: "center" }}>
              <Text style={{ color: ui().page, fontSize: 32, fontWeight: "700" }}>{index() + 1}</Text>
            </View>
          </View>
        )}
      </Each>
    </Scroll>
  );
  const toTop = (compact: boolean) => (
    <View
      onPress={() => scroller.scrollTo({ y: 0, animated: true })}
      {...button("secondary", { size: compact ? "md" : "sm" })}
    >
      <Text style={buttonText()}>scrollTo top</Text>
    </View>
  );

  return (
    <View style={{ flex: 1, backgroundColor: ui().page, paddingTop: 24, gap: 12 }}>
      {() =>
        wide() ? (
          <View style={{ flex: 1, paddingHorizontal: 20, paddingBottom: 20, gap: 14 }}>
            <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>scroll</Text>
            <Text style={{ color: ui().muted }}>
              {desktop ? "Shift+wheel or swipe the trackpad across the pages; the wheel scrolls the rows" : "Swipe the pages and the rows"}
            </Text>
            <View style={{ flex: 1, flexDirection: "row", gap: 16 }}>
              <View style={{ flex: 1, minWidth: 0, gap: 12 }}>
                {pager(0, { height: 150, flexGrow: 0, borderRadius: 16 })}
                {/* The scroll view fills its region, so its scrollbar sits at the region's edge. */}
                <View style={{ flex: 1, borderRadius: 16, borderWidth: 1, borderColor: ui().line, overflow: "hidden" }}>
                  <Scroll ref={scroller} style={{ flex: 1 }} scrollEventThrottle={16} onScroll={(e) => y.set(e.offset.y)}>
                    <View style={{ padding: 12, gap: 6 }}>
                      <Each of={rows}>
                        {(n) => (
                          <View style={{ ...ui().row, borderRadius: 8, height: size.row, paddingHorizontal: 12, justifyContent: "center" }}>
                            <Text style={{ color: ui().text, fontSize: size.label }}>Row {n()}</Text>
                          </View>
                        )}
                      </Each>
                    </View>
                  </Scroll>
                </View>
              </View>
              <Inspector>
                <Panel title="Horizontal, pagingEnabled · onMomentumEnd">
                  <Text style={{ fontSize: 13, color: ui().text, fontVariant: ["tabular-nums"] }}>
                    page {page() + 1} of {colors().length}
                  </Text>
                </Panel>
                <Panel title="Vertical · onScroll">
                  <Text style={{ fontSize: 13, color: ui().text, fontVariant: ["tabular-nums"] }}>y = {Math.round(y())}</Text>
                </Panel>
                {toTop(true)}
              </Inspector>
            </View>
          </View>
        ) : (
          <>
            <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text, paddingHorizontal: 20 }}>scroll</Text>

            <Text style={{ color: ui().muted, paddingHorizontal: 20 }}>
              Horizontal, pagingEnabled · page {page() + 1} · {desktop ? "Shift+wheel or swipe the trackpad" : "swipe"}
            </Text>
            {pager(12, { height: 140, flexGrow: 0 })}

            <View style={{ width: "100%", maxWidth: 640, alignSelf: "center", flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingHorizontal: 20 }}>
              <Text style={{ color: ui().muted }}>Vertical · y = {Math.round(y())}</Text>
              {toTop(false)}
            </View>
            <Scroll ref={scroller} style={{ flex: 1 }} scrollEventThrottle={16} onScroll={(e) => y.set(e.offset.y)}>
              <View style={{ width: "100%", maxWidth: 640, alignSelf: "center", paddingHorizontal: 20, paddingBottom: 20, gap: 8 }}>
                <Each of={rows}>
                  {(n) => (
                    <View style={{ ...ui().row, borderRadius: 12, padding: 14 }}>
                      <Text style={{ color: ui().text }}>Row {n()}</Text>
                    </View>
                  )}
                </Each>
              </View>
            </Scroll>
          </>
        )
      }
    </View>
  );
}

mount(App);
use nsh_core::prelude::*;

scroll().flex_1().child(
    view().p_4().gap_2().child(each(
        rows,
        |row: &Row| row.id,
        |row, _index| text(move || row.get().title),
    )),
)

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

स्क्रोल व्यू को अपनी अक्ष के अनुदिश एक सीमित आकार चाहिए: उसे flex: 1 (.flex_1()) दें, या ऐसे कंटेनर के अंदर ऊँचाई दें जिसकी ऊँचाई तय हो। इसका कंटेंट स्क्रोल व्यू की चौड़ाई पर (क्षैतिज होने पर ऊँचाई पर) और जितनी ऊँचाई (चौड़ाई) की उसे ज़रूरत हो उतनी पर लेआउट होता है।

#Props

सामान्य props के अलावा (style को ViewStyle टाइप के साथ)। Rust में, स्क्रोलिंग props Scrollable trait के मेथड हैं, जिन्हें lists भी साझा करती हैं।

#Scrolling

PropRustप्रकारडिफ़ॉल्टविवरण
horizontal.horizontal()booleanfalseबगल की ओर (क्षैतिज) स्क्रोल करता है।
scrollable.scrollable(..)booleantrueउपयोगकर्ता इसे स्क्रोल कर सकता है।
scrollbar.scrollbar(..)boolean | ScrollbarThemetrueस्क्रोल इंडिकेटर दिखता है: प्लेटफ़ॉर्म का, या थीम सेट होने के बाद ऐप का बिल्ट-इन बार; ऑब्जेक्ट देने पर वह व्यू की अपनी थीम होती है। डेस्कटॉप और डेस्कटॉप ब्राउज़रों में क्षैतिज व्यू इसे बनाए रखता है: यह माउस का स्क्रोल बार है।
bounces.bounces(..)booleantrueकिनारों से आगे ओवरस्क्रोल।
pagingEnabled.paging(..)booleanfalseव्यूपोर्ट के गुणजों पर रुकता है।
snapToInterval.snap_interval(px(..))number0इस लंबाई के गुणजों पर रुकता है (0: बंद)।
snapToOffsets.snap_offsets(..)number[]इन ऑफ़सेट पर रुकता है।
snapToAlignment.snap_alignment(SnapAlignment::Center)"start" | "center" | "end""start"snapToInterval के साथ आइटम का कौन-सा बिंदु व्यूपोर्ट से संरेखित होता है।
disableIntervalMomentum.disable_interval_momentum(..)booleanfalseफ्लिंग अधिकतम एक स्नैप पॉइंट तक ही जाती है।
decelerationRate.deceleration(rate)"normal" | "fast" | numberप्लेटफ़ॉर्मफ्लिंग कितनी तेज़ी से धीमी होती है: प्रति मिलीसेकंड बची हुई वेलोसिटी (normal 0.998, fast 0.99)।
contentInset.content_inset(EdgeInsets { .. })Partial<Edges>कंटेंट के चारों ओर जगह।
contentOffset.content_offset(point(..)){ x?, y? }यह कहाँ से शुरू होता है।
contentStyleकंटेंट व्यू की अपनी स्टाइलViewStyleचाइल्ड के चारों ओर एक व्यू की स्टाइल, जो उनके साथ स्क्रोल होता है; flexGrow: 1 इसे कम से कम व्यूपोर्ट जितना ऊँचा बनाता है (केंद्र में खाली स्थिति)।
contentClassकंटेंट व्यू की अपनी स्टाइलstringclasses जैसा ही, जैसे "grow justify-center p-4"।
keyboardDismissMode.keyboard_dismiss_mode(KeyboardDismissMode::OnDrag)"none" | "on-drag" | "interactive""none"ड्रैग करने पर कीबोर्ड बंद होता है या नहीं।
keyboardShouldPersistTaps.keyboard_taps(KeyboardTaps::Handled)"never" | "always" | "handled" | boolean"never"टैप करने पर कीबोर्ड बंद होता है या नहीं: never (टैप केवल कीबोर्ड बंद करता है), always (कीबोर्ड बना रहता है), handled (जब कोई चीज़ टैप को संभालती है तो कीबोर्ड बना रहता है)।
scrollValue.scroll_value(&value)AnimatedValueस्क्रोल ऑफ़सेट (मुख्य अक्ष) से भरा जाने वाला एनिमेटेड मान, स्क्रोल-लिंक्ड एनिमेशन के लिए।
scrollEventThrottle.event_throttle(ms)numberonScroll इवेंट्स के बीच न्यूनतम मिलीसेकंड (वैसे भी प्रति फ़्रेम अधिकतम एक)।

#Pull to refresh

PropRustप्रकारविवरण
refreshing.refreshing(..)booleanरिफ़्रेश स्पिनर दिखता है।
onRefresh.on_refresh(..)() => voidउपयोगकर्ता ने रिफ़्रेश के लिए खींचा: लोडिंग शुरू करें और खत्म होने तक refreshing सेट रखें।
refreshIndicator.refresh_indicator(Some(height)){ height: number }ऐप अपना खुद का इंडिकेटर बनाता है, जो height पॉइंट ऊँचा है: प्लेटफ़ॉर्म का स्पिनर छिपा दिया जाता है, height तक पहुँचने पर पुल रिफ़्रेश करता है, और रिफ़्रेश होते समय कंटेंट के ऊपर height बना रहता है। 0 या उससे कम ऊँचाई का मतलब कोई इंडिकेटर नहीं।
pullValue.pull_value(&value)AnimatedValueएक एनिमेटेड मान जिसमें यह भरा जाता है कि व्यू को उसके शीर्ष से कितना आगे खींचा गया है (विश्राम पर 0, खिंचाव के साथ बढ़ता है; रिफ़्रेश के दौरान कंटेंट के ऊपर रखी गई जगह: height के साथ refreshIndicator), ऐप के इंडिकेटर के लिए।
let refreshing = signal(false);

scroll()
    .flex_1()
    .refreshing(refreshing)
    .on_refresh(move || {
        refreshing.set(true);
        spawn(async move {
            load().await;
            refreshing.set(false);
        });
    })
    .child(content())

#Zooming

maximumZoomScale को minimumZoomScale से ऊपर सेट करने पर (Rust में .zoom_range(min, max)) कंटेंट पिंच से ज़ूम करने योग्य हो जाता है; ज़ूम इन होने पर वह दोनों दिशाओं में स्क्रोल होता है। Lists अपना स्केल बनाए रखती हैं।

PropRustप्रकारडिफ़ॉल्टविवरण
minimumZoomScale.zoom_range(min, max)number1सबसे छोटा ज़ूम।
maximumZoomScale.zoom_range(min, max)number1सबसे बड़ा ज़ूम।
zoomScale.zoom(..)numberबदलने पर इस स्केल पर ज़ूम करता है; अन्यथा उपयोगकर्ता का ज़ूम बना रहता है।
bouncesZoom.bounces_zoom(..)booleantrueपिंच सीमाओं से आगे जा सकता है और वापस स्प्रिंग होता है।
zoomable.zoomable(..)booleantrueउपयोगकर्ता ज़ूम करने के लिए पिंच कर सकता है।
centerContent.center_content(..)booleanfalseव्यूपोर्ट से छोटा कंटेंट (ज़ूम आउट होने पर) केंद्र में रहता है।
let photo = element_ref();

scroll()
    .element_ref(&photo)
    .zoom_range(1.0, 4.0)
    .center_content(true)
    .flex_1()
    .bg(black())
    .child(
        image(PICTURE)
            .w(px(390.0))
            .h(px(520.0))
            .on_press(move || photo.zoom_to(1.0, None, true)),
    )

#Events

EventRustPayloadकब
onScroll.on_scrollScrollEventऑफ़सेट बदला (प्रति फ़्रेम अधिकतम एक बार, और scrollEventThrottle से अधिक बार नहीं)।
onScrollDragStart / onScrollDragEnd.on_scroll_drag_start / .on_scroll_drag_end{ offset } (Point<Points>)उपयोगकर्ता ने ड्रैग करना शुरू / बंद किया।
onMomentumStart / onMomentumEnd.on_momentum_start / .on_momentum_end{ offset }ड्रैग के बाद की ग्लाइड शुरू / बंद हुई। नए ड्रैग से रोकी गई ग्लाइड भी onMomentumEnd के साथ खत्म होती है।
onScrollEnd.on_scroll_end{ offset }स्क्रोलिंग रुक गई।
onRefresh.on_refreshकोई नहींरिफ़्रेश के लिए खींचा गया।

ScrollEvent है { offset: Point; contentSize: Size; size: Size; zoomScale } (Rust में offset, content_size, size, zoom_scale): ऑफ़सेट, (ज़ूम किया हुआ) कंटेंट आकार, व्यूपोर्ट आकार और ज़ूम स्केल (जब तक व्यू ज़ूम न हो, 1)।

#Ref methods

मेथडRustविवरण
scrollTo({ x?, y?, animated? })scroll_to(point(x, y), animated)किसी ऑफ़सेट तक स्क्रोल करता है।
zoomTo({ scale, x?, y?, animated? })zoom_to(scale, Some(point(x, y)), animated)scale तक ज़ूम करता है (सीमाओं के भीतर रखते हुए), कंटेंट पॉइंट (x, y, बिना ज़ूम वाले पॉइंट) को व्यूपोर्ट के बीच में रखते हुए, या बीच के आसपास। जैसे डबल टैप से टैप किए गए बिंदु पर ज़ूम इन करना।
let scroller = element_ref();
scroll().element_ref(&scroller).child(content());

scroller.scroll_to(point(px(0.0), px(0.0)), true);

#Keyboard

स्क्रोल व्यू के अंदर के इनपुट नेटिव रूप से कीबोर्ड से दूर रखे जाते हैं: स्क्रोल व्यू को नीचे का इनसेट मिलता है और वह फ़ोकस किए गए इनपुट तक अपने आप स्क्रोल करता है। स्क्रोल व्यू के बाहर के कंटेंट के लिए नीचे की पैडिंग या मार्जिन में env(keyboard-inset-height) का उपयोग करें। देखें forms and the keyboard।

#Right to left

राइट-टू-लेफ़्ट लेआउट में क्षैतिज स्क्रोल व्यू दाएँ सिरे से शुरू होते हैं और कंटेंट बदलने पर उससे अपनी दूरी बनाए रखते हैं; उनके चाइल्ड मिरर किए जाते हैं।

#Platform notes

  • Android: पुल टू रिफ़्रेश NSH द्वारा बनाया जाता है (ओवरस्क्रोल नेटिव रहता है), contentInset पैडिंग के रूप में लागू होता है, और decelerationRate स्नैपिंग ग्लाइड को आकार देता है।
  • Android पर ज़ूम NSH के अपने स्क्रोल व्यू से होता है, जो कंटेंट को उसके ऊपरी बाएँ कोने के आसपास स्केल करता है और दोनों दिशाओं में स्क्रोल करता है। पिंच Android की उँगलियों के बीच की न्यूनतम दूरी (लगभग 27 मिमी) के बाद शुरू होते हैं।
  • Mac Catalyst (Mac idiom) पर, NSH पुल का पता लगाता है और अपना स्पिनर दिखाता है।
  • iOS ज़ूम खत्म होने पर टेक्स्ट और कैनवास को ज़ूम किए हुए रेज़ोल्यूशन पर फिर से बनाता है।