Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีทำให้ Layout เลื่อนแนวตั้ง (Vertical Scroll) ใน Android

ภาพรวม

ScrollView (Vertical ScrollView) เป็น ViewGroup ที่เลื่อนเนื้อหาในแนวตั้ง (Vertical) รองรับ **Child เดียวเท่านั้น** (ต้องห่อด้วย LinearLayout/ConstraintLayout) ใช้สำหรับหน้าที่เนื้อหายาวกว่าหน้าจอ

ขั้นตอนการสร้าง

1. Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    android:scrollbars="vertical"
    android:fadeScrollbars="true"
    android:overScrollMode="always">

    <!-- Child เดียว: LinearLayout แนวตั้ง -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="หัวข้อใหญ่: คู่มือการใช้งาน ScrollView"
            android:textSize="24sp"
            android:textStyle="bold"
            android:layout_marginBottom="16dp" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="centerCrop"
            android:src="@drawable/sample_image_1"
            android:contentDescription="รูปภาพตัวอย่าง 1"
            android:layout_marginBottom="16dp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="เนื้อหายาวๆ หลายๆ ย่อหน้า...\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
            android:textSize="16sp"
            android:lineSpacingExtra="4dp"
            android:layout_marginBottom="24dp" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="centerCrop"
            android:src="@drawable/sample_image_2"
            android:contentDescription="รูปภาพตัวอย่าง 2"
            android:layout_marginBottom="16dp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="เนื้อหาต่อไป...\n\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
            android:textSize="16sp"
            android:lineSpacingExtra="4dp"
            android:layout_marginBottom="24dp" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ปุ่มท้ายหน้า" />

    </LinearLayout>

</ScrollView>

Attributes สำคัญ:

  • android:fillViewport="true" - ขยาย Child ให้เต็ม Viewport (ป้องกัน ScrollView สั้นกว่าจอ)
  • android:scrollbars="vertical" - แสดง Scrollbar
  • android:fadeScrollbars="true" - Scrollbar จางหายอัตโนมัติ
  • android:overScrollMode="always|ifContentScrolls|never" - พฤติกรรม Overscroll Effect

NestedScrollView (สำหรับ Nested Scrolling)

หาก ScrollView อยู่ใน CoordinatorLayout หรือมี Nested Scrolling (เช่น RecyclerView ใน ScrollView) ให้ใช้ **NestedScrollView**:

<androidx.core.widget.NestedScrollView
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout ...>
        <!-- เนื้อหา รวมถึง RecyclerView ที่ตั้งค่า setNestedScrollingEnabled(false) -->
    </LinearLayout>

</androidx.core.widget.NestedScrollView>

โค้ดควบคุม Scroll (Programmatic Scrolling)

ScrollView scrollView = findViewById(R.id.scrollView);

// เลื่อนไปด้านล่างสุด (Smooth)
scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN));

// เลื่อนไปด้านบนสุด
scrollView.post(() -> scrollView.fullScroll(View.FOCUS_UP));

// เลื่อนไปตำแหน่งเฉพาะ (Smooth)
scrollView.smoothScrollTo(0, targetY);

// เลื่อนไป View เฉพาะ
View targetView = findViewById(R.id.targetView);
scrollView.post(() -> {
    int[] location = new int[2];
    targetView.getLocationOnScreen(location);
    // คำนวณ offset ตาม ScrollView
    scrollView.smoothScrollTo(0, location[1] - scrollView.getTop());
});

Scroll Listener (ฟังเหตุการณ์ Scroll)

scrollView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
    // scrollY = ตำแหน่งปัจจุบันจากด้านบน
    // ใช้สำหรับ: Parallax, Hide/Show Toolbar, Load More, Progress Bar
    
    if (scrollY == 0) {
        // อยู่ด้านบนสุด
    }
    
    // ตรวจสอบถึงด้านล่าง
    View child = scrollView.getChildAt(0);
    if (child != null && scrollY >= (child.getHeight() - scrollView.getHeight())) {
        // ใกล้ถึงด้านล่าง → Load more
    }
});

ปัญหาที่พบบ่อยและแก้ไข

ปัญหาสาเหตุแก้ไข
Scroll ไม่ได้ / ไม่เลื่อนChild height ≤ ScrollView heightเพิ่มเนื้อหา, หรือ android:fillViewport="true"
RecyclerView ใน ScrollView Scroll ไม่ได้Nested Scrolling Conflictrv.setNestedScrollingEnabled(false) หรือใช้ NestedScrollView
Keyboard บังเนื้อหาSoft Input ModeAndroidManifest: android:windowSoftInputMode="adjustResize"
Scroll จERKY/LagLayout ซับซ้อน, รูปใหญ่ใช้ RecyclerView, ลด Nesting, ใช้ ConstraintLayout

Best Practices

  • Child เดียวเท่านั้น (ห่อด้วย LinearLayout/ConstraintLayout)
  • ใช้ fillViewport="true" เพื่อให้ Child ขยายเต็มจอ
  • หลีกเลี่ยง ScrollView ซ้อน ScrollView / RecyclerView ใน ScrollView (ใช้ NestedScrollView)
  • รูปภาพขนาดใหญ่ → ใช้ Glide/Picasso + override size, หรือ WebP
  • สำหรับ List ข้อมูลเยอะ → ใช้ **RecyclerView** แทน (มี View Recycling)

สรุป

ScrollView = Vertical Scrolling Container สำหรับเนื้อหาคงที่/ไม่มาก ใช้ fillViewport=true, Child เดียว, หลีกเลี่ยง Nested Scrolling สำหรับ List ข้อมูล Dynamic ให้ใช้ RecyclerView (ซึ่ง Scroll เองได้แล้ว) NestedScrollView สำหรับ CoordinatorLayout/Collapsing Toolbar