Accessibility Trait: สาระสำคัญ ประเภท และวิธีการทำงานในการพัฒนา

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-05-16 เวลาอ่าน: 9 นาที

Accessibility Trait คือคุณสมบัติขององค์ประกอบ iOS ที่กำหนดบทบาทและพฤติกรรมสำหรับ VoiceOver เทรตจะบอกโปรแกรมอ่านหน้าจอว่าองค์ประกอบควรถูกอ่านอย่างไรและมีท่าทางใดบ้างที่ใช้ได้: ไม่ว่าจะเป็นปุ่ม หัวเรื่อง ลิงก์ หรือช่องค้นหา ตามข้อมูลจาก Apple UIAccessibilityTraits, 2024 ระบบรองรับค่าคงที่กว่า 15 รายการที่สามารถรวมกันได้โดยใช้บิตมาสก์ การเลือกเทรตที่ถูกต้องช่วยประหยัดเวลาในการนำทางได้ถึง 50% สำหรับผู้ใช้ VoiceOver

ประเด็นสำคัญ

  • Accessibility Trait — บทบาทขององค์ประกอบ iOS สำหรับ VoiceOver; กำหนดผ่านค่าคงที่ UIAccessibilityTraits
  • เทรตสามารถรวมกันได้โดยใช้ตัวดำเนินการ | เพื่อสร้างบทบาทที่ซับซ้อน (ปุ่ม + เลือกแล้ว)
  • แต่ละองค์ประกอบสามารถมีหลายเทรตพร้อมกันได้ แต่ไม่เกิน 3-4 เพื่อหลีกเลี่ยงความสับสน
  • เทรตที่ไม่ถูกต้อง (เช่น StaticText สำหรับปุ่ม) ทำลายสถานการณ์การโต้ตอบ: ผู้ใช้ไม่รู้ว่ามีท่าทางที่ใช้ได้หรือไม่
  • ใน Android สิ่งที่เทียบเท่าคือแอตทริบิวต์ role และ className ใน AccessibilityNodeInfo

Accessibility Trait คืออะไร

Accessibility Trait คือแฟล็กที่ตั้งบนองค์ประกอบ UIView เพื่อระบุบทบาทเชิงความหมายให้ VoiceOver เทรตเป็นหนึ่งในสามองค์ประกอบของสามกลุ่มการช่วยเหลือของ Apple: Label (ชื่อ), Hint (คำอธิบาย), Trait (บทบาท) iOS ใช้บิตมาสก์ UIAccessibilityTraits (UInt64) ซึ่งแต่ละบิตสอดคล้องกับบทบาทเฉพาะ VoiceOver อ่านบทบาทหลังจาก Label และ Hint: “ปุ่มส่ง จะเปิดแบบฟอร์ม” — “ปุ่ม” ถูกเพิ่มขึ้นด้วยเทรต UIAccessibilityTraitButton

โดยค่าเริ่มต้น UIButton จะได้รับ UIAccessibilityTraitButton, UILabel จะได้รับ UIAccessibilityTraitStaticText, UIImageView จะได้รับ UIAccessibilityTraitImage เมื่อใช้ตัวควบคุมแบบกำหนดเอง นักพัฒนาจะต้องตั้งค่าเทรตด้วยตนเอง Apple Human Interface Guidelines, 2024 เรียกสิ่งนี้ว่า “หนึ่งในขั้นตอนที่สำคัญที่สุดในการรับประกันการช่วยเหลือ”

หากไม่มีเทรตที่ถูกต้อง ผู้ใช้จะไม่รู้ว่าควรใช้ท่าทางใด: แตะครั้งเดียว (การเปิดใช้งานปุ่ม), แตะสองครั้ง (ซูม) หรือท่าทางปัด (สวิตช์) เทรตจะกำหนดว่าท่าทาง VoiceOver ใดที่จะเปิดใช้งานบนองค์ประกอบ

การใช้งานทางเทคนิคของ UIAccessibilityTraits

UIAccessibilityTraits คือ typealias UInt64 แต่ละเทรตเป็นค่าคงที่ที่มีการตั้งค่าบิตเดียวเท่านั้น ตัวอย่างเช่น UIAccessibilityTraitButton = 0x0000000000000001, UIAccessibilityTraitLink = 0x0000000000000002, UIAccessibilityTraitHeader = 0x0000000000000008 การรวมกันทำได้โดยใช้ OR ระดับบิต: 0x0001 | 0x0008 = 0x0009 VoiceOver วิเคราะห์มาสก์และกำหนดพฤติกรรม

ประเภทหลักของเทรต iOS

iOS มีค่าคงที่เทรตมากกว่า 15 รายการ มาดูประเภทหลักที่ใช้ใน 90% ของสถานการณ์:

เทรตค่าคงที่พฤติกรรม VoiceOver
ButtonUIAccessibilityTraitButtonเปิดใช้งานด้วยการแตะสองครั้ง
HeaderUIAccessibilityTraitHeaderนำทางด่วนตามหัวเรื่อง
LinkUIAccessibilityTraitLinkเปิดใช้งานเป็นลิงก์
StaticTextUIAccessibilityTraitStaticTextอ่านอย่างเดียว ไม่มีการเปิดใช้งาน
SearchFieldUIAccessibilityTraitSearchFieldช่องค้นหาที่มีพฤติกรรมพิเศษ
ImageUIAccessibilityTraitImageรูปภาพ ไม่มีท่าทางเปิดใช้งาน
SelectedUIAccessibilityTraitSelectedสถานะ “เลือกแล้ว”
PlaysSoundUIAccessibilityTraitPlaysSoundเล่นเสียงเมื่อเปิดใช้งาน
KeyboardKeyUIAccessibilityTraitKeyboardKeyปุ่มแป้นพิมพ์
TabBarUIAccessibilityTraitTabBarองค์ประกอบแถบแท็บ

ค่าคงที่พร้อมใช้งานใน UIKit ตั้งแต่ iOS 3.0 iOS 14+ เพิ่มการรองรับ UIAccessibilityTraits ใน SwiftUI ผ่านตัวปรับแต่ง .accessibilityAddTraits()

เทรตที่หายากแต่มีประโยชน์

UIAccessibilityTraitAdjustable — สำหรับค่าที่ปรับได้ (แถบเลื่อน, ตัวเลือก, แถบเลื่อนระดับเสียง) VoiceOver อนุญาตให้ปัดขึ้น/ลงเพื่อเปลี่ยนค่าด้วยขั้นตอนที่กำหนดผ่าน accessibilityIncrement และ accessibilityDecrement UIAccessibilityTraitUpdatesFrequently — สำหรับองค์ประกอบที่มีค่าเปลี่ยนแปลงบ่อย (ตัวจับเวลา, ตัวบ่งชี้ความคืบหน้า) VoiceOver จะไม่อ่านค่าในทุกการเปลี่ยนแปลง แต่จะหยุดชั่วคราว UIAccessibilityTraitAllowsDirectInteraction — สำหรับองค์ประกอบที่ผู้ใช้สามารถโต้ตอบได้โดยตรง (แป้นพิมพ์, การวาด) โดยข้ามท่าทาง VoiceOver

การรวมเทรต

องค์ประกอบเดียวสามารถมีหลายเทรตพร้อมกันได้ — การรวมถูกตั้งค่าโดยใช้ OR ระดับบิต (|) ตัวอย่าง: ปุ่มที่ถูกเลือกอยู่ในขณะนี้ — Button | Selected VoiceOver จะประกาศ: “เลือกแล้ว กรองตามราคา ปุ่ม”

การตั้งค่าเทรตในโค้ด:

swift
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)

// หรือผ่านมาสก์:
filterButton.accessibilityTraits = [.button, .selected]

สำหรับ UIView ที่กำหนดเองซึ่งไม่ได้ตั้งค่าเทรตโดยค่าเริ่มต้น:

swift
class CustomToggle: UIControl {
    override var accessibilityTraits: UIAccessibilityTraits {
        get {
            if isOn {
                return [.button, .selected]
            } else {
                return .button
            }
        }
        set {}
    }
}

กฎการรวม: ไม่เกิน 3-4 เทรต ต่อองค์ประกอบ เทรตที่มากเกินไป (เช่น Button + Link + Header) ทำให้การประกาศ VoiceOver ยาวและสับสนเกินไป ตามข้อมูลของ Apple “คุณสมบัติเพิ่มเติมแต่ละอย่างจะเพิ่มภาระทางความคิดของผู้ใช้”

SwiftUI: ตัวปรับแต่งเทรต

ใน SwiftUI เทรตถูกตั้งค่าโดยใช้ตัวปรับแต่ง .accessibilityAddTraits() และ .accessibilityRemoveTraits() ตัวอย่าง: Text(“หัวเรื่อง”).font(.largeTitle).accessibilityAddTraits(.isHeader) ตัวปรับแต่ง .isHeader จะเพิ่ม UIAccessibilityTraitHeader รายการเทรต SwiftUI: .isButton, .isHeader, .isLink, .isSelected, .isImage, .isSearchField, .isKeyboardKey, .isStaticText, .isSummaryElement, .isToggle, .playsSound, .startsMediaSession, .updatesFrequently, .allowsDirectInteraction, .causesPageTurn, .isModal, .tabBar

ข้อผิดพลาดทั่วไปในการเลือกเทรต

StaticText แทน Button — ตัวควบคุมที่กำหนดเองซึ่งดูเหมือนปุ่มจะได้รับเทรต StaticText โดยค่าเริ่มต้น VoiceOver จะไม่มีท่าทางเปิดใช้งาน ดังนั้นผู้ใช้จึงไม่สามารถ “กด” องค์ประกอบได้ วิธีแก้ไข: ตั้งค่า .button อย่างชัดเจน

รูปภาพไม่มีเทรต — UIImageView ที่เปิดใช้งานการช่วยเหลือจะได้รับเทรต Image แม้ว่าจริงๆ แล้วมันคือปุ่มสำหรับขยายรูปภาพ กำหนด .button และ Label “ขยายรูปภาพ” ตามข้อมูลจาก WWDC 2023, “Deliver an Exceptional Accessibility Experience” 40% ของการถดถอยด้านการช่วยเหลือในเวอร์ชันแอปใหม่เกิดจากความไม่ตรงกันของเทรต

Header ในทุกองค์ประกอบ — เทรต Header มีไว้สำหรับหัวเรื่องโครงสร้างของหน้าจอ หากทำให้ทุก UILabel เป็นหัวเรื่อง โรเตอร์ VoiceOver ในโหมด “หัวเรื่อง” จะไร้ประโยชน์ — มันจะหยุดทุกคำ

วิธีแก้ไข: รายการตรวจสอบ

  • แต่ละองค์ประกอบที่กำหนดเองแบบโต้ตอบจะได้รับเทรต Button, Link หรือ Adjustable
  • หัวเรื่องส่วนจะได้รับเทรต Header (ไม่ใช่ StaticText)
  • ปุ่มรูปภาพจะได้รับเทรต Button + Selected เมื่ออยู่ในสถานะเลือกแล้ว
  • องค์ประกอบที่ไม่มีท่าทาง — StaticText หรือ Image (อ่านอย่างเดียว)

บั๊กถดถอยเมื่อเปลี่ยน UIButton เป็น UIControl

สาเหตุทั่วไปของการสูญเสียเทรตคือการปรับโครงสร้าง: นักพัฒนาเปลี่ยน UIButton เป็น UIControl สำหรับการแสดงผลแบบกำหนดเอง UIButton จะได้รับเทรต Button โดยอัตโนมัติ แต่ UIControl ไม่ได้รับ หลังจากการปรับโครงสร้าง คุณต้องตั้งค่า accessibilityTraits = .button อย่างชัดเจน เพิ่มการตรวจสอบในการตรวจสอบโค้ด: “หากคุณเปลี่ยน UIButton เป็น UIControl — ให้ตรวจสอบเทรต”

เทรตและสถานะไดนามิก

สำหรับองค์ประกอบที่มีสถานะเปลี่ยนแปลง (เช่น ปุ่มถูกใจ) เทรตควรเปลี่ยนแบบไดนามิก ในสถานะ “ไม่ถูกใจ” — Button ในสถานะ “ถูกใจ” — Button + Selected + Image (หากมีไอคอน) VoiceOver เปลี่ยนแปลงการประกาศ: “ถูกใจ ปุ่ม” เทียบกับ “เลือกแล้ว ถูกใจ ปุ่ม” ใช้ accessibilityValue เพื่อสื่อสารสถานะหากเทรต Selected ไม่เพียงพอ เกี่ยวข้องกับปุ่มสมัครสมาชิก รายการโปรด ตัวกรอง และสวิตช์

สิ่งที่เทียบเท่าใน Android: role และ className

ใน Android ไม่มีสิ่งที่เทียบเท่าโดยตรงกับเทรต แทนที่จะใช้บิตมาสก์ จะใช้สิ่งต่อไปนี้:

  • className — ค่าของ AccessibilityNodeInfo.className (android.widget.Button, android.widget.TextView)
  • role — แอตทริบิวต์ XML (บทบาทถูกกำหนดโดยประเภทของ View)
  • stateDescription — สิ่งที่เทียบเท่ากับ Selected: การเพิ่มคำอธิบายสถานะ (เปิด/ปิด)

สำหรับ View ที่กำหนดเองใน Android คุณต้องแทนที่ onInitializeAccessibilityNodeInfo:

kotlin
class CustomButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    override fun onInitializeAccessibilityNodeInfo(
        info: AccessibilityNodeInfo
    ) {
        super.onInitializeAccessibilityNodeInfo(info)
        info.className = "android.widget.Button"
        info.isClickable = true
    }
}

นักพัฒนา Flutter ควรใช้พารามิเตอร์ semanticsRole ในวิดเจ็ต Semantics: button, header, image, link, textField และอื่นๆ นอกจากนี้ยังมี semanticsLabel และ semanticsHint — สิ่งที่เทียบเท่าเต็มรูปแบบของสามกลุ่ม iOS Label + Hint + Trait

สิ่งที่เทียบเท่าในเว็บ: บทบาท WAI-ARIA

สำหรับเวอร์ชันเว็บของแอปพลิเคชันมือถือ (PWA, WebView) จะใช้แอตทริบิวต์ role จาก WAI-ARIA: role="button", role="heading", role="link" นี่คือสิ่งที่เทียบเท่าโดยตรงของ accessibilityTraits ในแอปพลิเคชันไฮบริด ให้ตรวจสอบว่า WebView ส่งผ่านบทบาท ARIA ไปยังชั้นการช่วยเหลือดั้งเดิม ในการทำเช่นนี้ ให้ใช้โปรโตคอล UIAccessibilityContainerDataTable ใน iOS หรือ setAccessibilityDelegate ใน Android WebView ที่เปิดใช้ JavaScript อาจไม่ส่งผ่านบทบาท ARIA อย่างถูกต้อง — ทดสอบแยกต่างหาก

AccessibilityNodeInfo: การกระทำเพิ่มเติม

ใน Android คุณสามารถเพิ่มการกระทำที่กำหนดเองใน AccessibilityNodeInfo: AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK และ ACTION_LONG_CLICK นี่คือสิ่งที่เทียบเท่ากับเทรต Button ที่มีท่าทางเพิ่มเติม สำหรับแถบเลื่อน ให้ใช้ ACTION_SET_PROGRESS — สิ่งที่เทียบเท่ากับ Adjustable สำหรับ Spinner และ DatePicker — ACTION_SET_SELECTION, ACTION_SET_DATE และ ACTION_SET_TIME

การตรวจสอบและทดสอบเทรต

Xcode Accessibility Inspector เป็นเครื่องมือหลักสำหรับ iOS: เลือกองค์ประกอบและดูฟิลด์ Traits จะแสดงรายการเทรตที่ตั้งไว้ โรเตอร์ VoiceOver ในโหมด “องค์ประกอบ” ช่วยให้สามารถนำทางผ่านตัวควบคุมทั้งหมดบนหน้าจอ

การทดสอบอัตโนมัติใน Swift เพื่อตรวจสอบเทรต:

swift
func testSubmitButtonTrait() {
    let app = XCUIApplication()
    app.launch()
    let submitButton = app.buttons["ส่ง"]
    XCTAssertTrue(submitButton.isEnabled)
    // XCUIElement ไม่ให้การเข้าถึงเทรตโดยตรง
    // การตรวจสอบผ่านการเปิดใช้งานท่าทาง
    submitButton.tap()
    XCTAssertTrue(app.staticTexts["ส่งแบบฟอร์มแล้ว"].exists)
}

การตรวจสอบด้วยตนเอง ผ่าน VoiceOver: เปิด VoiceOver ปัดไปยังองค์ประกอบ แตะสองครั้ง — องค์ประกอบควรเปิดใช้งานหากเป็น Button หากองค์ประกอบไม่ตอบสนองต่อการแตะสองครั้ง แสดงว่าเทรตไม่ถูกต้อง ใช้ท่าทาง Rotor เพื่อสลับระหว่างโหมด (“หัวเรื่อง”, “ลิงก์”, “ปุ่ม”) — แต่ละโหมดจะแสดงเฉพาะองค์ประกอบที่มีเทรตที่เกี่ยวข้อง

การทดสอบหน่วยของเทรตใน iOS

ก่อน iOS 14 การทดสอบหน่วยไม่สามารถเข้าถึง accessibilityTraits ได้โดยตรง ตั้งแต่ iOS 14 เป็นต้นไป คุณสมบัตินี้พร้อมใช้งาน: XCTAssertEqual(customButton.accessibilityTraits, .button) ใช้สิ่งนี้ในการทดสอบหน่วยเพื่อตรวจสอบตัวควบคุมที่กำหนดเอง แนะนำให้ทดสอบ UIView ที่กำหนดเองใหม่ทุกครั้งเพื่อความถูกต้องของเทรต โดยเฉพาะหลังจากการปรับโครงสร้างหรือเปลี่ยนแปลงคลาสแม่

คำถามที่พบบ่อย

สามารถกำหนดเทรตให้กับองค์ประกอบหนึ่งได้กี่เทรต?

สูงสุด 3-4 เทรต ต่อองค์ประกอบ จำนวนที่มากกว่าทำให้การประกาศ VoiceOver ซ้ำซ้อน ใช้การรวม: Button + Selected, Header + StaticText

เทรตเริ่มต้นของ UIButton คืออะไร?

UIAccessibilityTraitButton iOS จะตั้งค่าให้โดยอัตโนมัติสำหรับอินสแตนซ์ UIButton ทั้งหมด หากคุณสืบทอดจาก UIView และจำลองปุ่ม จะต้องตั้งค่าเทรตด้วยตนเอง

มีเทรต “Adjustable” หรือไม่ และใช้ทำอะไร?

ใช่ UIAccessibilityTraitAdjustable — สำหรับองค์ประกอบที่มีค่าที่ปรับได้ (แถบเลื่อน, ตัวเลือก, ตัวนับ) VoiceOver อนุญาตให้ปัดขึ้น/ลงเพื่อเปลี่ยนค่าและอ่านสถานะปัจจุบัน

วิธีตรวจสอบเทรตใน SwiftUI?

ใช้ตัวปรับแต่ง .accessibilityAddTraits(): Text(“หัวเรื่อง”).font(.title).accessibilityAddTraits(.isHeader) เมธอดนี้ทำงานบน iOS 14+

จะเกิดอะไรขึ้นหากฉันไม่ตั้งค่าเทรตให้กับตัวควบคุมที่กำหนดเอง?

VoiceOver จะกำหนดเทรต None องค์ประกอบจะไม่มีบทบาท — โปรแกรมอ่านหน้าจอจะอ่านเฉพาะ Label โดยไม่ระบุประเภท ผู้ใช้จะไม่รู้ว่ามีท่าทางเปิดใช้งานหรือไม่

สรุป

  • Accessibility Trait — บิตมาสก์ UIAccessibilityTraits ที่กำหนดบทบาทขององค์ประกอบ iOS สำหรับ VoiceOver (Button, Header, Link, StaticText และอื่นๆ)
  • เทรตถูกรวมโดยใช้ OR ระดับบิต ([] ใน Swift) ไม่เกิน 3-4 ต่อองค์ประกอบ
  • UIView ที่กำหนดเองต้องได้รับเทรตที่ชัดเจน — โดยค่าเริ่มต้นอาจเป็น None หรือ Image
  • ใน Android บทบาทถูกกำหนดผ่าน className ใน AccessibilityNodeInfo ใน Flutter — ผ่าน semanticsRole
  • เทรตที่ไม่ถูกต้อง (StaticText สำหรับปุ่ม) ทำลายสถานการณ์ VoiceOver: ไม่มีท่าทางเปิดใช้งาน
  • ตรวจสอบเทรตผ่าน Accessibility Inspector ใน Xcode และโรเตอร์ VoiceOver
  • ใน SwiftUI ใช้ .accessibilityAddTraits() เพื่อกำหนดค่าเทรตแบบประกาศ

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม