التخطّي إلى المحتوى
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
البدءWebReactSwiftUIJetpack ComposeFlutterReact Nativeالإعدادات الجاهزةنظام التصميم الخاص بكاستخدام Tanrei مع وكلاء الذكاء الاصطناعيالعلامة التجاريةرموز التصميمأنظمة التصميم والتخصيصTheme Studioاللونالطباعةالأيقوناتالشكلالارتفاعالحركةحالات التفاعلالسلوكالتخطيطإمكانية الوصولالكلماترموز الألوانرموز السلّم الطباعيرموز الشكلرموز الارتفاعرموز الحركةرموز الحالةرموز التباعد والقياسالمكوّناتالزرزر الإجراء الرئيسيالزر المقسَّممجموعة الأزرارزر مع قائمةشريط الأدواتزر النسخخانة الاختيارزر الاختيارمفتاح التبديلالرقاقةقائمة الخياراتشريط التمريرحقل شريط التمريرالتقويمDateTimePickerمجموعة الحقولمجموعة أزرار الاختيارمجموعة خانات الاختيارعنصر الاختيارحقل الاختيارشريط القوائمرفع الملفاتمنتقي الملفات متقدّمساحة الإفلاتحقل إدخال النص متقدّمحقل النصحقل الرقاقاتالحقلمربع التحرير والسرد متقدّمحقل التحرير والسردحقل إدخال العدد متقدّمحقل العددحقل إدخال اللون متقدّمحقل اللونحقل إدخال الرمز لمرة واحدة متقدّمحقل الرمز لمرة واحدةحقل إدخال النص المدمج متقدّممربع كتابة الرسائلالبطاقةالفاصلالطبقة النمطية متقدّممربع الحوارالقائمة (list)صف القائمةاللوحة السفليةاللوحة الجانبيةالعرض الدوّاركتلة الشيفرةالجدولاللوحة المنبثقةالخطواتالأكورديونقائمة الوصفالشكل التوضيحيهيكل التطبيقرأس الصفحةالعرض الشجريالخط الزمنيمعاينة الصورمقبض تغيير الحجمالإطار القابل لتغيير الحجممنطقة التمريرالشارةمؤشر التقدمالعدّادعارض الأرقام المتحرّكمؤشر التحميلشريط الإشعار (Snackbar)التلميحاختصار لوحة المفاتيحالوسمالشيفرة المضمَّنةالتنويهالصورة الرمزيةالحالة الفارغةمجموعة الوسومهيكل التحميلعنصر الملفمربع اللونالنص المتحركعلامات التبويبعرض التبويباتشريط التطبيقشريط التنقلدرج التنقلالبحثالرابطالتنقل بين الصفحاتروابط السابق والتاليمؤشر الخطواتمسار التنقلجدول المحتوياتبطاقة الرابطقائمة FABالحالةكيف يُبنى Tanreiالمساهمةالترخيص والإسناد
الرئيسيةالمكوّناتالزر المقسَّم

الزر المقسَّم

يتيح للأشخاص اختيار خيار واحد، أو عدة خيارات، من خيارين إلى خمسة خيارات مترابطة مرسومة جنبًا إلى جنب مقاطعَ متصلة لعنصر تحكم واحد.

content_copyعرض بتنسيق Markdown
الفئة
الإجراءات
الرموز
comp.segmented-button
المستوى
أساسي

نظرة عامة

Web
tanrei-segmented-button
schedule
SwiftUI
TanreiSegmentedButton
schedule
Jetpack Compose
TanreiSegmentedButton
schedule
Flutter
TanreiSegmentedButton
schedule
React Native
SegmentedButton
schedule

مولَّد من docs/status/status.json, specs/segmented-button.spec.json

ليس في كل أنظمة التصميم

متوفر في cupertino, m3-expressive-like, m3-like، وتسجّله @tanrei/web/cupertino, @tanrei/web/m3-expressive-like, @tanrei/web/m3-like.

غير موجود في tanrei. One choice among several is told by what it changes: tabs where it switches the content below, radio buttons where it sets a value, a button group where each button toggles on its own. استخدم Tabs, Radio button, Button group بدلًا منه.

يمكن لمنتج مبني على نظام لا يتضمّنه أن يستخدمه مع ذلك: أدرجه في طبقتك الخاصة (نظام التصميم الخاص بك) واستورد وحدته الخاصة. عندها يُرسم برموز نظامك الخاص.

"components": {
  "include": ["segmented-button"]
}
import '@tanrei/web/components/segmented-button';

تحديد واحد، مع أيقونات، أيقونة فقط

مع m3-like

الاستخدام

يحمل الزر المقسَّم مقاطعه بالطريقة التي تحمل بها كل منصة الأبناء المتكررين: عناصر أبناء على الويب، وعروض في view builder على SwiftUI، واستدعاءات في content lambda على Compose، وقائمة segments على Flutter، ومصفوفة items على React Native. التحديد يخص المجموعة، بالقيمة. والخاصية selection تقول هل هو قيمة واحدة أم عدة قيم.

<tanrei-segmented-button label="النطاق" value="week">
  <tanrei-segment value="day" label="يوم"></tanrei-segment>
  <tanrei-segment value="week" label="أسبوع"></tanrei-segment>
  <tanrei-segment value="month" label="شهر"></tanrei-segment>
</tanrei-segmented-button>

<!-- عدة قيم معًا. values خاصية (مصفوفة)؛ والسمة تأخذ مصفوفة JSON أو قيمًا تفصل بينها مسافات. -->
<tanrei-segmented-button id="days" selection="multiple" size="small" label="الأيام" values="mon tue">
  <tanrei-segment value="mon" label="الاثنين"></tanrei-segment>
  <tanrei-segment value="tue" label="الثلاثاء"></tanrei-segment>
  <tanrei-segment value="wed" label="الأربعاء" disabled></tanrei-segment>
</tanrei-segmented-button>

<script type="module">
  import '@tanrei/web/components/segmented-button';
  // العنصر يحدّث value أو values الخاصة به، ثم يُصدر الحدث change.
  document.querySelector('[label="النطاق"]').addEventListener('change', (e) => showRange(e.detail.value));
  document.querySelector('#days').addEventListener('change', (e) => setDays(e.detail.values));
</script>
// يستبعد النظام الافتراضي الزر المقسَّم: تجده في مداخل m3-like وm3-expressive-like وcupertino، وفي /all.
import { Segment, SegmentedButton } from '@tanrei/react/m3-like';

// detail هو { value } للاختيار الواحد و { values } لعدة اختيارات.
<SegmentedButton label="النطاق" value={range} onChange={(e) => 'value' in e.detail && setRange(e.detail.value)}>
  <Segment value="day" label="يوم" />
  <Segment value="week" label="أسبوع" />
  <Segment value="month" label="شهر" />
</SegmentedButton>

<SegmentedButton selection="multiple" label="الأيام" values={days} onChange={(e) => 'values' in e.detail && setDays(e.detail.values)}>
  <Segment value="mon" label="الاثنين" />
  <Segment value="tue" label="الثلاثاء" />
  <Segment value="wed" label="الأربعاء" disabled />
</SegmentedButton>
import Tanrei

// نوع الربط (binding) هو التحديد: قيمة اختيارية لواحد، و Set لعدة.
// طبّق .tag و .labelStyle على TanreiSegment نفسه، قبل أي مُعدِّل آخر.
TanreiSegmentedButton("النطاق", selection: $range) {
    TanreiSegment("يوم").tag("day")
    TanreiSegment("أسبوع").tag("week")
    TanreiSegment("شهر").tag("month")
}

// .labelStyle(.iconOnly) هو labelHidden: العنوان يبقى اسم المقطع.
TanreiSegmentedButton("محاذاة النص", selection: $alignment) {
    TanreiSegment("محاذاة لليسار", icon: "format_align_left").tag("start").labelStyle(.iconOnly)
    TanreiSegment("توسيط", icon: "format_align_center").tag("center").labelStyle(.iconOnly)
    TanreiSegment("محاذاة لليمين", icon: "format_align_right").tag("end").labelStyle(.iconOnly)
}
import io.github.chnotchy.tanrei.components.TanreiSegment
import io.github.chnotchy.tanrei.components.TanreiSegmentedButton
import io.github.chnotchy.tanrei.components.TanreiSegmentedButtonSelectionMode
import io.github.chnotchy.tanrei.primitives.TanreiText
import io.github.chnotchy.tanrei.tokens.TanreiSegmentedButtonSize

// رد نداء واحد لنوعَي التحديد. المجموعة ذات الاختيار الواحد تمرّر مجموعة من عنصر واحد.
TanreiSegmentedButton(
    onSelectionChange = { range = it.single() },
    contentDescription = "النطاق",
    selectedValue = range,
) {
    TanreiSegment(value = "day", label = "يوم")
    TanreiSegment(value = "week", label = "أسبوع")
    TanreiSegment(value = "month", label = "شهر")
}

TanreiSegmentedButton(
    onSelectionChange = { days = it },
    contentDescription = "الأيام",
    selectionMode = TanreiSegmentedButtonSelectionMode.Multiple,
    selectedValues = days,
    size = TanreiSegmentedButtonSize.Small,
) {
    TanreiSegment(value = "mon", label = "الاثنين")
    TanreiSegment(value = "tue", label = "الثلاثاء")
    // يستخدم Compose الراية المعاكسة.
    TanreiSegment(value = "wed", label = "الأربعاء", enabled = false)
}

// labelHidden يرسم الأيقونة وحدها. والتسمية تبقى اسم المقطع.
TanreiSegment(value = "start", label = "محاذاة لليسار", labelHidden = true, icon = { TanreiText("format_align_left") })
import 'package:tanrei/tanrei.dart';

// على هيئة SegmentedButton: Set واحدة تحمل التحديد، وفيها عضو واحد على الأكثر في الاختيار الواحد.
TanreiSegmentedButton<String>(
  semanticLabel: 'النطاق',
  selected: <String>{range},
  onSelectionChanged: (Set<String> value) => setState(() => range = value.single),
  segments: const <TanreiSegment<String>>[
    TanreiSegment<String>(value: 'day', label: 'يوم'),
    TanreiSegment<String>(value: 'week', label: 'أسبوع'),
    TanreiSegment<String>(value: 'month', label: 'شهر'),
  ],
);

TanreiSegmentedButton<String>(
  semanticLabel: 'الأيام',
  multiSelectionEnabled: true,
  size: TanreiSegmentedButtonSize.small,
  selected: days,
  onSelectionChanged: (Set<String> value) => setState(() => days = value),
  segments: const <TanreiSegment<String>>[
    TanreiSegment<String>(value: 'mon', label: 'الاثنين'),
    TanreiSegment<String>(value: 'tue', label: 'الثلاثاء'),
    TanreiSegment<String>(value: 'wed', label: 'الأربعاء', enabled: false),
  ],
);

// labelHidden يرسم الأيقونة وحدها. والتسمية تبقى اسم المقطع.
const TanreiSegment<String>(value: 'start', label: 'محاذاة لليسار', icon: Icon(AppSymbols.formatAlignLeft), labelHidden: true);
import { SegmentedButton } from '@tanrei/react-native';

// متحكَّم به: onSelectionChange يستقبل القيمة (single) أو القيم (multiple).
<SegmentedButton
  accessibilityLabel="النطاق"
  value={range}
  onSelectionChange={setRange}
  items={[
    { value: 'day', label: 'يوم' },
    { value: 'week', label: 'أسبوع' },
    { value: 'month', label: 'شهر' },
  ]}
/>

<SegmentedButton
  selectionMode="multiple"
  accessibilityLabel="الأيام"
  size="small"
  values={days}
  onSelectionChange={setDays}
  items={[
    { value: 'mon', label: 'الاثنين' },
    { value: 'tue', label: 'الثلاثاء' },
    { value: 'wed', label: 'الأربعاء', disabled: true },
  ]}
/>

// مقطع بأيقونة فقط: { value: 'start', label: 'محاذاة لليسار', icon: 'format_align_left', labelHidden: true }

المواصفات

الأحجام والمقاطع المعطَّلة

مع m3-like

البنية

الجزء الوصف
1 set The row that holds the segments: its fill, its outline and its outer corners. It gives the segments equal widths, draws the dividers between them and moves keyboard focus among them.
2 container One segment: the area that carries hover, focus and press, its selected fill, and its hit area.
3 check · اختياري The check a selected segment shows before its label, in place of its icon when it has one: the glyph check of the system's icon set, drawn with the icon set's family, fill, weight and optical size. The segmented button draws no mark of its own. Not drawn in an icon-only segment, nor where the system's check size is 0.
4 icon · اختياري A glyph before the label, or alone in an icon-only segment.
5 label The segment's text and its accessible name. It may be hidden for an icon-only segment (labelHidden) and still name it.
6 divider The line between two neighbouring segments.
7 outline The border around the whole set, drawn inside its edge.
8 focus-ring Gap-then-ring indicator shown for keyboard focus, drawn inside the focused segment.

الخصائص

الخاصية النوع القيمة الافتراضية الوصف
selection single | multiple "single" single lets people choose one option at a time, as a radio group does; multiple lets them switch each option on and off.
value string null The value of the selected segment while selection is single; null selects none. The segmented button sets it when a segment is activated and emits change; the product may also set it.
values strings The values of the selected segments while selection is multiple: a list of strings (the platforms take a set). An empty list selects none.
size small | medium | large "medium" Visual height (32 / 36 / 40), matching Button's heights so that the set can share a row with buttons. The hit area always meets the minimum target. A design system may add values.
label string "" The accessible name of the set: the question its options answer ("Range", "Text alignment"). Required.

الأحداث

الحدث الوصف
change The user changed the selection; carries value (single) or values (multiple) after the change, which the set now holds.

العناصر

أنواع العناصر التي يكررها المكوّن. يسرد كل نموذج اختبار عناصره بالترتيب، وتسمّي كل منصة كل نوع بأسلوبها.

segment

One option of the set: a label, an optional icon, and the value that selects it.

الخاصية النوع القيمة الافتراضية الوصف
value string "" Identifies the segment: the set's value or values name it by this, and change carries it. Unique within the set; required.
label string "" The segment's text and its accessible name. Required, even when labelHidden is true.
icon string "" The name of an icon (a glyph of the system's icon set). Give every segment of a set an icon, or none.
labelHidden boolean false Draws the icon alone and keeps label as the accessible name (an icon-only segment).
disabled boolean false Prevents choosing or clearing the segment; the arrow keys skip it.
المواصفة Web SwiftUI Jetpack Compose Flutter React Native
العنصر tanrei-segment TanreiSegment TanreiSegment TanreiSegment Segment
value · الخاصية value tag value value value
label · الخاصية label title label label label
icon · الخاصية icon icon icon icon icon
labelHidden · الخاصية labelHidden labelStyle labelHidden labelHidden labelHidden
disabled · الخاصية disabled disabled enabled enabled disabled
ملاحظات A child element: <tanrei-segment value="week" label="Week" icon="…">, with label-hidden and disabled attributes, as <option> in a <select>. TanreiSegment(_ title:, icon:).tag(value) in the view builder, as a Picker's tagged options; .labelStyle(.iconOnly) is labelHidden; disabled follows .disabled(_:). TanreiSegment(value, label, icon, labelHidden, enabled) called in the TanreiSegmentedButton { } content lambda. enabled is the inverse flag. TanreiSegment<T>(value:, label:, icon:, labelHidden:, enabled:) in the segments: list. enabled is the inverse flag. The element type of the set's items array: { value, label, icon?, labelHidden?, disabled? }, where icon is the glyph's name.

الحالات

السلوك

متطلبات بصيغة EARS. يُختبر تنفيذ كل منصة مقابل هذه المعرّفات. يُعرض نص المتطلبات كما ورد في ملف المواصفة، بالإنجليزية.

المعرّف المتطلب
SEG-1 WHEN the user activates an enabled segment by pointer, touch, Enter or Space WHILE selection is single and value is not that segment's value THE segmented button SHALL set value to the segment's value, so that the segment that was selected becomes unselected, and emit change exactly once with it; WHEN the segment is already selected THE segmented button SHALL change nothing and emit nothing, because a single choice is never cleared by its own segment.
SEG-2 WHEN the user activates an enabled segment by pointer, touch, Enter or Space WHILE selection is multiple THE segmented button SHALL add the segment's value to values, or remove it when values holds it, and emit change exactly once with the new values; values may become empty.
SEG-3 WHILE a segment's disabled is true THE segmented button SHALL NOT select or clear it or emit change for it, SHALL skip it with the arrow keys, SHALL NOT make it the Tab stop and SHALL expose the disabled state to assistive technology.
SEG-4 WHILE a segment is hovered, keyboard-focused or pressed THE segmented button SHALL render its container, label, icon, check, elevation and opacity from the component tokens of its condition (selected or unselected) in the highest-precedence active state, with precedence pressed over focused over hovered; focus gained by pointer or touch SHALL NOT select the focused state. A part the interaction states recolor changes over the component's state motion; only a change of condition uses the selection motion (SEG-16).
SEG-5 WHEN a segment receives keyboard focus THE segmented button SHALL show the focus ring inside the segment's container, where the set's outline and the neighbouring segments cannot cover or clip it, without animation; focus gained by pointer or touch SHALL NOT show it.
SEG-6 WHERE the set is shorter than the minimum target THE segmented button SHALL extend each segment's hit area above and below the set to sys.target.touch for touch input and sys.target.pointer for fine pointers without changing its visual size, and SHALL make each segment at least as wide as that target, because neighbouring segments cannot extend a hit area over each other; a platform that cannot tell the input type SHALL use sys.target.touch.
SEG-7 WHILE a segment's disabled is true THE segmented button SHALL render its container, label, icon, check, elevation and opacity from the disabled component tokens of its condition; the set's outline and the dividers SHALL keep their colors, so that the set keeps a visible boundary.
SEG-8 WHEN size names a value that the active design system does not have THE segmented button SHALL render with the default value's tokens, and in debug builds report the unknown value.
SEG-9 WHEN the segment is pressed by pointer, touch, Enter or Space THE segment SHALL show the pressed state without delay and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner.
SEG-10 WHILE pressed THE segment SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container at once; ripple grows the pressed state layer from the point of contact (from the center for keyboard activation); dim applies the pressed opacity to the whole control and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; label, icon, check, elevation, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.segmented-button.motion.feedback-duration with comp.segmented-button.motion.state-easing, fades over the state duration of its size (comp.segmented-button.motion.state-duration.small, .medium or .large) with comp.segmented-button.motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced.
SEG-11 THE segment SHALL ease its container corners by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0) and show its keyboard focus as sys.behavior.focus-style names (ring or glow); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README.
SEG-12 THE segmented button SHALL render a segment from the selected condition (comp.segmented-button.selected.container.color and the other selected parts) WHILE selection is single and value equals the segment's value, or selection is multiple and values holds it, and every other segment from the unselected condition (comp.segmented-button.unselected.container.color and so on); WHEN value or values names no segment THE segmented button SHALL select nothing for that name, and WHEN a segment's value is empty or repeats another segment's THE segmented button SHALL still render it and treat the first segment with a value as the one that value selects; in debug builds it SHALL report each of these.
SEG-13 THE segmented button SHALL lay its segments out in one row, in order, in a set at least the container height of its size tall (comp.segmented-button.container.height.medium for medium, and so on), filled with comp.segmented-button.set.color, with outer corners of comp.segmented-button.set.shape, an outline of comp.segmented-button.outline.width in comp.segmented-button.outline.color inside its edge, and its segments inset from that edge by comp.segmented-button.set.padding; the outer corners of the first and last segment SHALL be the set's corners less set.padding, so that the two curves stay concentric, and every other corner of a segment SHALL be comp.segmented-button.container.shape; each segment SHALL clip its fill, state layer and ripple to its own shape, and the set SHALL NOT clip a segment's elevation.
SEG-14 THE segmented button SHALL give every segment the same width: the widest segment's content plus the padding of its size on each side (comp.segmented-button.container.padding-inline.medium for medium, and so on), a segment's content being its leading glyph (its icon, or the check where one would be drawn), the gap of its size (comp.segmented-button.container.gap.medium, and so on) and its label, measured as if the segment were selected, so that selecting a segment never changes a width; WHERE the layout gives the set more width THE segmented button SHALL divide it equally among the segments, and WHERE less, it SHALL divide what it has equally and let labels wrap onto more lines rather than truncate, growing every segment to the tallest, with at least the padding-block of its size (comp.segmented-button.container.padding-block.medium, and so on) above and below.
SEG-15 THE segmented button SHALL centre a segment's content in it, the leading glyph first; SHALL set the label in the label style of its size (comp.segmented-button.label.typescale.medium, and so on) and the label color of its condition and state; and SHALL draw the icon in the icon color of its condition and state at the icon size of its size (comp.segmented-button.icon.size.medium, and so on) through the icon helper, with the family and fill of the segment's condition (selected for a selected segment, otherwise unselected), sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max.
SEG-16 WHILE a segment is selected and its label is drawn THE segmented button SHALL draw the glyph check of the system's icon set in the leading position, in place of the segment's icon when it has one, as the filter chip draws its check (CHP-13, CHP-14), at the check size of its size (comp.segmented-button.check.size.medium, and so on) in the icon color of the selected condition, with sys.icon.family.selected, sys.icon.fill.selected, the weight comp.segmented-button.check.weight (not sys.icon.weight: the check is a control's own mark drawn on the selected fill, as the checkbox's is, CHK-12) and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, and SHALL NOT mirror it when the layout direction is right-to-left; the weight SHALL change the stroke of the glyph only, the check's box staying its check size; THE segmented button SHALL draw no mark of its own (no path, shape or character of its own for the check). An icon-only segment SHALL keep its icon when selected and draw no check; WHILE the check size of the segment's size is 0 THE segmented button SHALL draw no check, reserve no room for it, and keep the icon. WHEN a segment becomes selected or unselected THE segmented button SHALL fade the check in or out (a glyph is not drawn along a path), cross-fading it with the icon where the segment has one, and change the segment's colors and elevation over comp.segmented-button.motion.selection-duration with comp.segmented-button.motion.selection-easing, re-centring the content as the check comes and goes, and SHALL show the new condition at once where motion is reduced.
SEG-17 THE segmented button SHALL draw a line of comp.segmented-button.divider.width in comp.segmented-button.divider.color between each two neighbouring segments, taking that width between them and running from the set's top padding to its bottom padding; the line SHALL keep its color and full opacity whatever the state or condition of either segment, and SHALL be hidden from assistive technology.
SEG-18 WHILE selection is single THE segmented button SHALL be one Tab stop — the selected segment, or the first enabled segment while none is selected; WHILE a segment has keyboard focus Right Arrow and Down Arrow SHALL move focus to the next enabled segment and Left Arrow and Up Arrow to the previous one, wrapping at the ends, and Home and End to the first and last enabled segment, and each move SHALL also select the segment it reaches and emit change, as a radio group does; in a right-to-left layout Left Arrow SHALL move to the next segment and Right Arrow to the previous.
SEG-19 WHILE selection is multiple THE segmented button SHALL be one Tab stop — the segment that had focus last, or else the first selected segment, or else the first enabled segment; WHILE a segment has keyboard focus Right Arrow and Down Arrow SHALL move focus to the next enabled segment and Left Arrow and Up Arrow to the previous one, wrapping at the ends, and Home and End to the first and last enabled segment, without changing the selection, and Space or Enter SHALL switch the focused segment (SEG-2); in a right-to-left layout Left Arrow SHALL move to the next segment and Right Arrow to the previous.
SEG-20 WHILE selection is single THE segmented button SHALL expose the set as a radio group named by label and each segment as a radio with its checked state; WHILE selection is multiple THE segmented button SHALL expose the set as a group named by label and each segment as a toggle button with its pressed state, as a toggle Button is; in both, each segment SHALL be named by its own label whether or not it is drawn, over a name the product gives the segment on the element (aria-label or aria-labelledby) and expose its position and the number of segments, and the icons, the check, the dividers and the outline SHALL be hidden.
SEG-21 WHEN the layout direction is right-to-left THE segmented button SHALL order the segments from the right, mirror each segment's content (the glyph to the right of the label) and apply its paddings by logical start and end, and SHALL grow a ripple from the point of contact as in left-to-right.
SEG-22 WHILE a segment's label is empty and the product gives the segment a name of its own on the element — aria-label, or aria-labelledby naming an element — THE segmented button SHALL expose that name as the segment's accessible name; WHILE a segment's label is empty and the product gives it none THE segmented button SHALL still render the segment, and in debug builds report that it has no accessible name; WHILE a segment's labelHidden is true and its icon is empty THE segmented button SHALL draw the label anyway and in debug builds report the segment; WHILE the set's label is empty, or the set holds fewer than two or more than five segments, THE segmented button SHALL still render and in debug builds report it.
SEG-23 WHEN the colors or the elevation of a segment change between interaction states THE segmented button SHALL animate them over the state duration of its size (comp.segmented-button.motion.state-duration.small, .medium or .large) with comp.segmented-button.motion.state-easing, and SHALL change them at once where motion is reduced.
SEG-24 WHILE a segment is selected THE segmented button SHALL cast the elevation of its condition and state (comp.segmented-button.selected.container.elevation at rest, and so on) outside the segment and above its neighbours; THE segmented button SHALL NOT position itself or draw anything outside the set but that elevation.
SEG-25 IF the icon set cannot draw the check yet (its font is still loading or failed to load) THE segmented button SHALL draw nothing in the check's place, never the glyph's name as text, SHALL keep the room SEG-14 measures for it so that no width changes, SHALL still expose the segment's selected state, and SHALL show the check once the icon set can draw it, without the selection motion of SEG-16.
SEG-26 THE segmented button SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the segmented button is shown THE segmented button SHALL draw itself for the new direction at once, without a motion of its own, keeping its selection and its focus.
SEG-27 WHERE the layout direction is right-to-left THE segmented button SHALL draw a segment's icon mirrored left to right exactly when the system's icon set marks that glyph's name as mirrored or the product forces mirroring for that use, and unmirrored when the product forbids it: the icon helper mirrors the glyph inside its own box, about the box's vertical centre line, changing neither its place, size, color and fill nor the order SEG-21 gives. THE segmented button SHALL NOT mirror a glyph itself, and SHALL NOT mirror content the product gives as an image or a view of its own rather than by a glyph's name. The check of a selected segment is never mirrored (SEG-16).
SEG-28 THE segmented button SHALL lay out a segment's label as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word, a number with its sign or unit, a telephone number and an address keep their own order in a right-to-left layout and reorder nothing beside them; THE segmented button SHALL still place each label and align its lines by the layout direction, not by the text's own.
SEG-29 WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on a segment's host, by the attribute or by the ARIA property that reflects it, THE segmented button SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on the element that carries the segment's role — an id reference by the elements it names in the host's tree or a tree around it, an error message as part of the description while the segment is invalid — except those a segment owns (aria-checked, aria-pressed, aria-disabled), which it SHALL move and not expose. WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE segmented button SHALL take it off that element. WHEN the product sets an aria- attribute a segment owns THE segmented button SHALL report it in debug builds. The set's host carries its radio group or group role itself (SEG-20), so what the product writes on it is not moved, but for a name: WHILE the set's label is not empty THE segmented button SHALL hold the product's aria-label and aria-labelledby on that host as their data-aria- twins, so that label is the set's whole name although the platform gives aria-labelledby the precedence, and WHEN label is emptied SHALL give them back as they were written; WHILE it is empty a name the product gives so is the set's name and SHALL NOT be reported as having none in debug builds (SEG-22); WHEN the product removes one, or its data-aria- twin, or sets the ARIA property that reflects it to null, THE segmented button SHALL take it away.

مطابقة الأسماء بين المنصات

التكافؤ لا يعني واجهات برمجية متطابقة. تعبّر كل منصة عن العقد نفسه بأسلوبها.

المواصفة Web SwiftUI Jetpack Compose Flutter React Native
المكوّن tanrei-segmented-button TanreiSegmentedButton TanreiSegmentedButton TanreiSegmentedButton SegmentedButton
selection · الخاصية selection selection selectionMode multiSelectionEnabled selectionMode
value · الخاصية value selection selectedValue selected value
values · الخاصية values selection selectedValues selected values
size · الخاصية size size size size size
label · الخاصية label label contentDescription semanticLabel accessibilityLabel
change · الحدث change selection onSelectionChange onSelectionChanged onSelectionChange
ملاحظات tanrei-segmented-button (selection, value, values, size, label) holds tanrei-segment children. value is an attribute and a property; values is a property (an array); the values attribute is also read, as JSON or as space-separated words, because the fixture harness writes attributes. It sets its own value or values before firing change, as a native control does. It puts role radiogroup (single) or group (multiple) and aria-label on its own element, and on each segment's inner <button> role radio with aria-checked, aria-posinset and aria-setsize (single), or aria-pressed (multiple), with a roving tabindex. A toggle button may not carry aria-posinset, so in a multiple set the row is a role="list" and each segment a role="listitem" that carries the position; ElementInternals is not used for the roles, because axe cannot see it. It is not form-associated. The check is the icon helper's check glyph in the check part (SEG-16). TanreiSegmentedButton(_ label:, selection: Binding<V?>, size:) { TanreiSegment … } for single selection and TanreiSegmentedButton(_ label:, selection: Binding<Set<V>>, size:) { … } for multiple: the binding's type is selection, and writing it is change. SwiftUI's Picker with .pickerStyle(.segmented) is not used: its segments cannot be tokenised. A single-choice segment is a button with the .isSelected trait and its position as its accessibility value; a multiple-choice segment adds the .isToggle trait (iOS 17). Lagging behind SEG-16 and SEG-25: without an installed icon font it strokes the check as a vector of its own (TanreiChipGlyph, on the checkbox's mark geometry) instead of drawing nothing. Lagging behind SEG-16's weight (the check drawn at comp.segmented-button.check.weight): its check is drawn at sys.icon.weight. One composable for both selections (Material's SingleChoiceSegmentedButtonRow and MultiChoiceSegmentedButtonRow in one): TanreiSegmentedButton(selectionMode, selectedValue, selectedValues, onSelectionChange, size, contentDescription) { TanreiSegment(…) }. State hoisting: the caller keeps selectedValue or selectedValues and moves it from onSelectionChange. The row is a selectableGroup(); a single-choice segment is selectable(role = Role.RadioButton) and a multiple-choice one toggleable(role = Role.Button), as the filter chip is. Compose has no radio group role. onSelectionChange is (Set<String>) -> Unit for both selections: a single choice passes a set of one (as the list does). Lagging behind SEG-16 and SEG-25: without an installed icon font it strokes the check as a vector of its own (TanreiDrawnGlyph, tanreiCheckPath) instead of drawing nothing. Lagging behind SEG-16's weight (the check drawn at comp.segmented-button.check.weight): its check is drawn at sys.icon.weight. Shaped like Flutter's SegmentedButton<T> but built with the widgets library, without Material: TanreiSegmentedButton<T>(segments:, selected: Set<T>, onSelectionChanged:, multiSelectionEnabled:, size:, semanticLabel:). selected holds zero or one value while multiSelectionEnabled is false; the caller moves it from onSelectionChanged. A single-choice segment is Semantics(inMutuallyExclusiveGroup: true, checked:) and a multiple-choice one Semantics(button: true, toggled:), inside a Semantics(container: true, label:) for the set. A single-choice set is exposed with SemanticsRole.radioGroup, named by semanticLabel (SEG-20). Lagging behind SEG-25: it writes the check as the Material Symbols code point U+E5CA (tanreiCheckGlyph), and without the icon font it draws whatever the fallback face has for that code point instead of nothing. Lagging behind SEG-16's weight (the check drawn at comp.segmented-button.check.weight): its check is drawn at sys.icon.weight. <SegmentedButton items={Segment[]} selectionMode value | values onSelectionChange size accessibilityLabel>; controlled, the caller moves value or values from onSelectionChange. The set has the radiogroup role (single) or the group role (multiple); each segment the radio role with accessibilityState.checked, or the button role with accessibilityState.selected, as a toggle Button is. The arrow keys work where a hardware keyboard is attached. Lagging behind SEG-25: it writes the ligature check into the glyph box, and without the icon font it prints the word instead of drawing nothing. Lagging behind SEG-16's weight (the check drawn at comp.segmented-button.check.weight): its check is drawn at sys.icon.weight.

الرموز

الرمز يشير إلى القيمة المحلولة (فاتح)
--tanrei-comp-segmented-button-check-size-large sys.icon.extra-small 16px
--tanrei-comp-segmented-button-check-size-medium sys.icon.extra-small 16px
--tanrei-comp-segmented-button-check-size-small sys.icon.extra-small 16px
--tanrei-comp-segmented-button-check-weight sys.icon.mark.weight 500
--tanrei-comp-segmented-button-container-gap-large sys.space.space100 8px
--tanrei-comp-segmented-button-container-gap-medium sys.space.space100 8px
--tanrei-comp-segmented-button-container-gap-small sys.space.space100 8px
--tanrei-comp-segmented-button-container-height-large — 40px
--tanrei-comp-segmented-button-container-height-medium — 36px
--tanrei-comp-segmented-button-container-height-small — 32px
--tanrei-comp-segmented-button-container-padding-block-large — 6px
--tanrei-comp-segmented-button-container-padding-block-medium — 6px
--tanrei-comp-segmented-button-container-padding-block-small — 6px
--tanrei-comp-segmented-button-container-padding-inline-large sys.space.space200 16px
--tanrei-comp-segmented-button-container-padding-inline-medium sys.space.space175 14px
--tanrei-comp-segmented-button-container-padding-inline-small sys.space.space150 12px
--tanrei-comp-segmented-button-container-shape sys.shape.corner.none 0px
--tanrei-comp-segmented-button-disabled-container-shape — 0px
--tanrei-comp-segmented-button-disabled-opacity — 1
--tanrei-comp-segmented-button-divider-color sys.color.outline #848484
--tanrei-comp-segmented-button-divider-width sys.border.hairline 1px
--tanrei-comp-segmented-button-focused-container-shape — 0px
--tanrei-comp-segmented-button-focused-opacity — 1
--tanrei-comp-segmented-button-hovered-container-shape — 0px
--tanrei-comp-segmented-button-hovered-opacity — 1
--tanrei-comp-segmented-button-icon-size-large sys.icon.extra-small 16px
--tanrei-comp-segmented-button-icon-size-medium sys.icon.extra-small 16px
--tanrei-comp-segmented-button-icon-size-small sys.icon.extra-small 16px
--tanrei-comp-segmented-button-motion-feedback-duration sys.motion.role.feedback 450ms
--tanrei-comp-segmented-button-motion-selection-duration sys.motion.role.selection.mark 250ms
--tanrei-comp-segmented-button-motion-selection-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-segmented-button-motion-state-duration-large sys.motion.role.state.large 250ms
--tanrei-comp-segmented-button-motion-state-duration-medium sys.motion.role.state.default 250ms
--tanrei-comp-segmented-button-motion-state-duration-small sys.motion.role.state.compact 200ms
--tanrei-comp-segmented-button-motion-state-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-segmented-button-outline-color sys.color.outline #848484
--tanrei-comp-segmented-button-outline-width sys.border.hairline 1px
--tanrei-comp-segmented-button-pressed-container-shape — 0px
--tanrei-comp-segmented-button-pressed-opacity — 1
--tanrei-comp-segmented-button-selected-container-color sys.color.secondary-container #eeeeee
--tanrei-comp-segmented-button-selected-container-elevation sys.elevation.level0
--tanrei-comp-segmented-button-selected-disabled-container-color — #1b1b1b · 12%
--tanrei-comp-segmented-button-selected-disabled-container-elevation —
--tanrei-comp-segmented-button-selected-disabled-icon-color — #1b1b1b · 38%
--tanrei-comp-segmented-button-selected-disabled-label-color — #1b1b1b · 38%
--tanrei-comp-segmented-button-selected-disabled-state-layer-color — #1b1b1b · 38%
--tanrei-comp-segmented-button-selected-focused-container-color — #dadada
--tanrei-comp-segmented-button-selected-focused-container-elevation —
--tanrei-comp-segmented-button-selected-focused-icon-color — #262626
--tanrei-comp-segmented-button-selected-focused-label-color — #262626
--tanrei-comp-segmented-button-selected-focused-state-layer-color — #262626
--tanrei-comp-segmented-button-selected-hovered-container-color — #dedede
--tanrei-comp-segmented-button-selected-hovered-container-elevation —
--tanrei-comp-segmented-button-selected-hovered-icon-color — #262626
--tanrei-comp-segmented-button-selected-hovered-label-color — #262626
--tanrei-comp-segmented-button-selected-hovered-state-layer-color — #262626
--tanrei-comp-segmented-button-selected-icon-color sys.color.on-secondary-container #262626
--tanrei-comp-segmented-button-selected-label-color sys.color.on-secondary-container #262626
--tanrei-comp-segmented-button-selected-pressed-container-color — #dadada
--tanrei-comp-segmented-button-selected-pressed-container-elevation —
--tanrei-comp-segmented-button-selected-pressed-icon-color — #262626
--tanrei-comp-segmented-button-selected-pressed-label-color — #262626
--tanrei-comp-segmented-button-selected-pressed-state-layer-color — #262626
--tanrei-comp-segmented-button-selected-state-layer-color comp.segmented-button.selected.label.color #262626
--tanrei-comp-segmented-button-set-color — #000000 · 0%
--tanrei-comp-segmented-button-set-padding sys.space.space0 0px
--tanrei-comp-segmented-button-set-shape sys.shape.corner.small 6px
--tanrei-comp-segmented-button-unselected-container-color — #000000 · 0%
--tanrei-comp-segmented-button-unselected-container-elevation sys.elevation.level0
--tanrei-comp-segmented-button-unselected-disabled-container-color — #000000 · 0%
--tanrei-comp-segmented-button-unselected-disabled-container-elevation —
--tanrei-comp-segmented-button-unselected-disabled-icon-color — #1b1b1b · 38%
--tanrei-comp-segmented-button-unselected-disabled-label-color — #1b1b1b · 38%
--tanrei-comp-segmented-button-unselected-disabled-state-layer-color — #1b1b1b · 38%
--tanrei-comp-segmented-button-unselected-focused-container-color — #1b1b1b · 10%
--tanrei-comp-segmented-button-unselected-focused-container-elevation —
--tanrei-comp-segmented-button-unselected-focused-icon-color — #4b4b4b
--tanrei-comp-segmented-button-unselected-focused-label-color — #1b1b1b
--tanrei-comp-segmented-button-unselected-focused-state-layer-color — #1b1b1b
--tanrei-comp-segmented-button-unselected-hovered-container-color — #1b1b1b · 8%
--tanrei-comp-segmented-button-unselected-hovered-container-elevation —
--tanrei-comp-segmented-button-unselected-hovered-icon-color — #4b4b4b
--tanrei-comp-segmented-button-unselected-hovered-label-color — #1b1b1b
--tanrei-comp-segmented-button-unselected-hovered-state-layer-color — #1b1b1b
--tanrei-comp-segmented-button-unselected-icon-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-segmented-button-unselected-label-color sys.color.on-surface #1b1b1b
--tanrei-comp-segmented-button-unselected-pressed-container-color — #1b1b1b · 10%
--tanrei-comp-segmented-button-unselected-pressed-container-elevation —
--tanrei-comp-segmented-button-unselected-pressed-icon-color — #4b4b4b
--tanrei-comp-segmented-button-unselected-pressed-label-color — #1b1b1b
--tanrei-comp-segmented-button-unselected-pressed-state-layer-color — #1b1b1b
--tanrei-comp-segmented-button-unselected-state-layer-color comp.segmented-button.unselected.label.color #1b1b1b
--tanrei-comp-segmented-button-label-typescale-large sys.typescale.label 500 14px/1.4286
--tanrei-comp-segmented-button-label-typescale-medium sys.typescale.label 500 14px/1.4286
--tanrei-comp-segmented-button-label-typescale-small sys.typescale.label 500 14px/1.4286

نماذج الاختبار

عروض مرجعية. تلتقط كل المنصات لقطة لكل نموذج بالمعرّف نفسه حتى يمكن مقارنة النتائج.

مولَّد من specs/segmented-button.spec.json, tokens/comp/segmented-button.tokens.json, design/tokens/

الإرشادات

متى يُستخدم

استخدم الزر المقسَّم حين يكون لسؤال صغير واحد بضع إجابات ثابتة وينبغي أن يراها الأشخاص كلها دفعة واحدة: نطاق مخطط بياني، تخطيط قائمة، محاذاة فقرة، الأيام التي يتكرر فيها تذكير. وينبغي أن يظهر الأثر فورًا، لأن مفاتيح الأسهم في التحديد الواحد تختار وهي تتحرك.

يناسبه خياران إلى خمسة خيارات. وإن زادت الخيارات على خمسة فاستخدم قائمة خيارات أو قائمة. وحين يكون الاختيار هو المهمة الرئيسية في نموذج، تُقرأ أزرار الاختيار أفضل. وحين تغيّر الإجابة المحتوى الذي يملأ الشاشة، استخدم علامات التبويب.

زر مقسَّم أم مجموعة أزرار أم رقاقات أم علامات تبويب

هذه الأربعة كلها تضع بضعة أشياء مترابطة في صف، فيسهل الخلط بينها. تختلف في ما تفعله الضغطة وفي طريقة تنقل لوحة المفاتيح خلالها.

المكوّن ما هو التحديد لوحة المفاتيح يُستخدم لـ
الزر المقسَّم عنصر تحكم واحد: خياران إلى خمسة خيارات متصلة تجيب عن سؤال واحد. خاص به، بالقيمة: خيار واحد، أو عدة خيارات. موضع توقف واحد للمفتاح Tab. مفاتيح الأسهم تنتقل بين الخيارات، وفي التحديد الواحد تختار أيضًا. إعداد له بضع إجابات ثابتة ويُطبَّق فورًا: يوم، أسبوع، شهر؛ اليسار، الوسط، اليمين.
مجموعة الأزرار صف أو عمود من أزرار منفصلة، متباعدة أو متصلة في شكل واحد. لا شيء. زر التبديل في المجموعة يحتفظ بحالة التشغيل أو الإيقاف الخاصة به. كل زر موضع توقف مستقل للمفتاح Tab. إجراءات مترابطة: «إلغاء»، «حفظ المسودة»، «نشر»؛ و«غامق» و«مائل» و«تسطير» أزرارَ تبديل مستقلة.
الرقاقات عناصر تحكم صغيرة منفصلة في صف يلتف أو يُمرَّر. كل رقاقة تصفية تُشغَّل أو تُوقَف بمفردها. كل رقاقة موضع توقف مستقل للمفتاح Tab. عوامل تصفية فوق قائمة، ردود مقترحة، عناصر أدخلها المستخدم.
علامات التبويب عروض لموضوع واحد، لكل منها لوحته الخاصة. علامة تبويب واحدة: العرض الظاهر على الشاشة. موضع توقف واحد للمفتاح Tab. مفاتيح الأسهم تنتقل وتحدّد. تبديل المحتوى المعروض: «نظرة عامة»، «النشاط»، «الإعدادات».

اختبار سريع: إن كان ضغطه يفعل شيئًا فهو مجموعة أزرار. وإن كان يضبط قيمة فهو زر مقسَّم، أو رقاقات حين تكثر الخيارات أو تكون مستقلة. وإن كان يبدّل المحتوى الذي تحته فهو علامات تبويب.

اختيار واحد أم عدة اختيارات

  • الاختيار الواحد (selection="single"، وهو الافتراضي) مجموعة أزرار اختيار. اختيار مقطع يلغي المقطع الذي قبله. وضغط المقطع المختار مرة أخرى لا يفعل شيئًا، فلا يمكن إلغاء الاختيار الواحد من مقطعه نفسه. يجوز أن تبدأ المجموعة بلا شيء مختار (الخاصية value فارغة)، لنموذج يجب أن يُظهر أن شيئًا لم يُختر بعد.
  • الاختيار المتعدد مجموعة أزرار تبديل. كل مقطع يُشغَّل ويُوقَف، وقد تنتهي المجموعة بلا مقطع مختار. إن كان منتجك يحتاج إلى مقطع واحد على الأقل، فلا تطبّق تغييرًا يترك المجموعة فارغة.

ليست للمجموعة خاصية disabled خاصة بها. عطّل المقاطع واحدًا واحدًا. المقطع المعطَّل يحتفظ بمكانه وبحدّه، ومفاتيح الأسهم تتخطاه.

التسميات والأيقونات وعلامة الاختيار

  • المقطع المحدَّد يعرض علامة اختيار قبل تسميته، مكان أيقونته حين تكون له أيقونة، فلا يُعرف التحديد بالتعبئة وحدها أبدًا. والمقطع ذو الأيقونة فقط يحتفظ بأيقونته ويرسمها معبَّأة. يجوز لنظام تصميم أن يضبط حجم علامة الاختيار على 0: فلا يرسم عندئذ علامة، ويُظهر التحديد بالتعبئة والارتفاع.
  • كل مقطع بعرض أعرض مقطع، مقيسًا كما لو كان محدَّدًا، فظهور علامة الاختيار لا يحرّك جارًا أبدًا. وإن ضاقت الفسحة التفّت التسميات على أسطر أكثر وكبر كل مقطع إلى ارتفاع أطولها. ولا تُقتطع أبدًا.
  • الخاصية labelHidden ترسم الأيقونة وحدها. والتسمية تبقى مطلوبة، لأنها تبقى الاسم المتاح للتقنيات المساعدة للمقطع.
  • الحجم يضبط ارتفاع المجموعة. والأحجام ليست ارتفاعات Button في كل درجة (في الإعداد الجاهز m3-like يطابق الحجمان small و medium ارتفاعَي Button والحجم large أقل)، فطابِق المجموعة مع الأزرار التي بجانبها بالارتفاع، لا باسم الحجم.

افعل

  • أعطِ المجموعة تسمية تطرح السؤال الذي تجيب عنه خياراتها: «النطاق»، «محاذاة النص».
  • اجعل التسميات كلمة أو كلمتين، ومتوازية في الصيغة: يوم، أسبوع، شهر.
  • أعطِ كل مقاطع المجموعة أيقونة، أو لا تعطِ أيًّا منها.
  • اختر قيمة ابتدائية حين يكون هناك افتراضي معقول، كي لا يبدو عنصر التحكم أبدًا بلا إجابة.

لا تفعل

  • لا تستخدم الزر المقسَّم للإجراءات. المقطع اختيار، ولا يُصدر الحدث click. استخدم مجموعة أزرار.
  • لا تستخدمه للتبديل بين عروض يملأ كل منها الشاشة. استخدم علامات التبويب.
  • لا تضع أكثر من خمسة مقاطع في مجموعة، ولا تسميات شديدة التفاوت في الطول. كل مقطع يأخذ عرض أعرضها.
  • لا تغيّر تسمية المقطع بتغيّر حالته. التحديد يُعلَن على حدة.

إمكانية الوصول

الدور
radiogroup
التسمية
The set is named by label: the question its options answer. Each segment is named by its own label, drawn or not (labelHidden). Icons, the check, the dividers and the outline are decorative: a segment's state is announced from its checked or pressed state, never from the check.
الحد الأدنى للهدف
تستوفي مساحة اللمس الحد الأدنى لحجم الهدف حتى لو كان الحجم المرئي أصغر. minimum 32px · pointer 44px · spacing 8px · touch 48px

لوحة المفاتيح

المفاتيح الإجراء
Tab / Shift+Tab Moves focus into the set (to the selected segment, the last focused one, or the first enabled one) and out of it.
Right Arrow / Down Arrow Moves focus to the next enabled segment, wrapping; with single selection it also selects it (Left Arrow in right-to-left layouts).
Left Arrow / Up Arrow Moves focus to the previous enabled segment, wrapping; with single selection it also selects it (Right Arrow in right-to-left layouts).
Home / End Moves focus to the first or last enabled segment; with single selection it also selects it.
Enter / Space Selects the focused segment (single) or switches it on or off (multiple).

ملاحظات

  • Single selection is a radio group: arrow keys move and select at once, as the radio button and tabs do, because a segment shows its effect without a noticeable delay. Multiple selection is a group of toggle buttons with one Tab stop: arrow keys only move focus, and Space or Enter switches.
  • Selection is the set's: value or values holds the selected segments' values, and change carries the new ones. A segment's disabled is its own.
  • iOS has no radio role: a segment of a single-choice set is a button with the selected trait and its position ("2 of 3") in its accessibility value, as the radio button is. Compose has no radio group role; the set is a selectable group and each segment `Role.RadioButton` (single) or a toggleable `Role.Button` (multiple), as the filter chip is.
  • A segmented button chooses among options of one setting. Actions belong to a button group; switching views of one subject belongs to tabs.
  • Text size does not clip a segment: labels wrap and every segment grows to the tallest. The icon is not text and keeps its size.
  • How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.

مولَّد من specs/segmented-button.spec.json, tokens/sys/measure.tokens.json

ما يتكفل به المكوّن

  • في التحديد الواحد تكون المجموعة مجموعة أزرار اختيار (radio group) تسمّيها تسميتها، وكل مقطع زر اختيار له حالة التحديد الخاصة به (checked). وفي التحديد المتعدد تكون المجموعة مجموعة (group) تسمّيها تسميتها، وكل مقطع زر تبديل له حالة الضغط الخاصة به.
  • كل مقطع تسمّيه تسميته الخاصة، مرسومةً كانت أو لا، ويعرّف بموضعه وبعدد المقاطع. الأيقونات وعلامة الاختيار والفواصل والحدّ مخفية. ولا تُعلَن الحالة من علامة الاختيار أبدًا.
  • المجموعة موضع توقف واحد للمفتاح Tab: المقطع المحدَّد، أو آخر مقطع نال التركيز في التحديد المتعدد، وإلا فأول مقطع مفعَّل. مفاتيح الأسهم تنتقل إلى المقطع المفعَّل التالي أو السابق وتدور عند الطرفين، والمفتاحان Home و End يصلان إلى الطرفين. في التحديد الواحد كل انتقال يحدّد أيضًا. وفي التحديد المتعدد يبدّل المفتاحان Space و Enter المقطع الذي عليه التركيز. في تخطيط من اليمين إلى اليسار ينتقل مفتاح السهم الأيسر إلى المقطع التالي.
  • المقاطع المعطَّلة تتخطاها مفاتيح الأسهم، ولا تكون موضع توقف المفتاح Tab أبدًا، وتُعرَّف للتقنيات المساعدة معطَّلة.
  • مساحة اللمس لكل مقطع تمتد فوق المجموعة وتحتها إلى الحد الأدنى للهدف، وعرض كل مقطع لا يقل عن هدف واحد، لأن الجيران لا يستطيع أحدهم أن يمتد فوق الآخر.
  • مؤشر التركيز يُرسم داخل المقطع الذي عليه التركيز، حيث لا يستطيع الحدّ ولا الجيران تغطيته. ويظهر عند التركيز بلوحة المفاتيح فقط.
  • عند أحجام النص الأكبر تلتف التسميات ويكبر كل مقطع إلى ارتفاع أطولها. والأيقونة تحتفظ بحجمها.
  • بنيات التنقيح (debug) تبلّغ عن غياب تسمية المجموعة أو المقطع، وعن تسمية مخفية بلا أيقونة، وعن قيمة أو قيم لا تسمّي أي مقطع، وعن قيمة مقطع فارغة أو مكررة، وعن مجموعة فيها أقل من مقطعين أو أكثر من خمسة مقاطع.

فجوات معروفة في المنصات:

  • على الويب، تعطي المجموعة ذات الاختيار المتعدد كل مقطع موضعه عبر قائمة حول المقاطع، لأن زر التبديل لا يستطيع أن يحمل موضعًا خاصًّا به.
  • ليس في SwiftUI دور مجموعة أزرار اختيار. المجموعة حاوية تسمّيها تسميتها. المقطع في مجموعة ذات اختيار واحد زر له الصفة selected وموضعه («2 of 3») قيمةً له، بالإنجليزية فقط حاليًّا. والمقطع في مجموعة ذات اختيار متعدد عنصر تبديل (toggle) ولا يذكر موضعًا، لأن قيمة خاصة به كانت ستحل محل حالة التشغيل أو الإيقاف في عنصر التبديل.
  • في SwiftUI: تأخذ المجموعة العرض المعروض عليها، كما يفعل segmented picker في SwiftUI. والمُعدِّل .fixedSize(horizontal: true, vertical: false) يُبقي عرضها الطبيعي. ظل المقطع وحلقة التركيز فيه يستخدمان أكبر زواياه على كل زاوية. وأيقونة SF Symbol المعطاة للمقطع لا تتحول إلى هيئتها المعبَّأة عند التحديد: مرّر الهيئة .fill منها بنفسك. ومفاتيح الأسهم مختبَرة بوصفها قواعد، لا بلوحة مفاتيح على المحاكي.
  • ليس في Compose دور مجموعة أزرار اختيار. المجموعة مجموعة قابلة للتحديد (selectable group)، وكل مقطع زر اختيار (single) أو زر قابل للتبديل (multiple)، كما هي رقاقة التصفية.
  • لا يعرّف Flutter بموضع المقطع ولا بعدد المقاطع، والمجموعة ذات الاختيار المتعدد حاوية تسمّيها تسميتها لا مجموعة (group)، لأن دلالات Flutter تخلو من الخاصيتين كلتيهما.
  • في React Native: العروض المتساوية تأتي من قياس كل تسمية بعد التخطيط الأول، فالمجموعة التي يكون أبوها أضيق منها في الإطار الأول قد تأخذ عرضًا أضيق من أعرض تسمياتها. ومفاتيح الأسهم على لوحة مفاتيح فعلية، وظل التحديد المرتفع فوق جيرانه على Android، لم تُفحص على جهاز.
  • تحت النظام cupertino، يكون ارتفاع المجموعتين small و medium 30 و 34 بدلًا من 28 و 32، والزوايا الداخلية للمقطعين الطرفيين أكثر استدارة من زواياهما الخارجية. وكلا الأمرين ينتظر قرارًا في الرموز (tokens) أو في المواصفة.

ما عليك فعله

  • أعطِ المجموعة تسمية، وكل مقطع تسمية، ومنها المقاطع ذات الأيقونة فقط.
  • اجعل أثر الاختيار يظهر فورًا، قرب عنصر التحكم. في التحديد الواحد يختار مستخدم لوحة المفاتيح بالتحرك، فالأثر البطيء يجعل مفاتيح الأسهم تبدو عالقة. وإن وجب أن يستغرق وقتًا، فاعرض التقدم حيث ستظهر النتيجة.
  • أعطِ المقاطع المعطَّلة سببًا قريبًا منها حين لا يكون واضحًا لماذا لا يمكن اختيارها.
  • على الويب ليس الزر المقسَّم عنصر تحكم في نموذج. لإرسال قيمته مع نموذج، انسخها إلى حقل إدخال مخفي من الحدث change.