Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách vô hiệu hóa (disable) ScrollView bằng code trong Android

Giới thiệu

Bài viết này hướng dẫn cách vô hiệu hóa cuộn (scroll) của ScrollView theo điều kiện hoặc hoàn toàn bằng code Java/Kotlin trong Android.

Các bước thực hiện

Bước 1: Tạo dự án mới

Khởi tạo project Android Studio mới.

Bước 2: Layout có ScrollView (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gravity="center"
            android:padding="16dp">

            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 2" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 3" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 4" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 5" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 6" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 7" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 8" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 9" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 10" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 11" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 12" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 13" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 14" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 15" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 16" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 17" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 18" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 19" />
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 20" />

        </LinearLayout>

    </ScrollView>

</RelativeLayout>

Bước 3: Code Java vô hiệu hóa ScrollView (src/MainActivity.java)

package app.com.sample;

import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private ScrollView scrollView;
    private boolean isScrollEnabled = true;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        scrollView = findViewById(R.id.scrollView);

        // Cách 1: setOnTouchListener - chặn hoàn toàn sự kiện touch
        scrollView.setOnTouchListener((v, event) -> {
            if (!isScrollEnabled) {
                Toast.makeText(MainActivity.this, "ScrollView đã bị vô hiệu hóa", Toast.LENGTH_SHORT).show();
                return true; // true = consume event, không cho scroll
            }
            return false; // false = cho phép xử lý bình thường
        });

        // Demo: Tự động disable sau 3 giây (tùy chọn)
        // scrollView.postDelayed(() -> {
        //     isScrollEnabled = false;
        //     Toast.makeText(this, "Scroll disabled!", Toast.LENGTH_SHORT).show();
        // }, 3000);
    }

    // Cách 2: Custom ScrollView class (tái sử dụng tốt hơn)
    public static class LockableScrollView extends ScrollView {
        private boolean scrollEnabled = true;

        public LockableScrollView(Context context) { super(context); }
        public LockableScrollView(Context context, AttributeSet attrs) { super(context, attrs); }
        public LockableScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }

        public void setScrollingEnabled(boolean enabled) {
            this.scrollEnabled = enabled;
        }

        public boolean isScrollingEnabled() {
            return scrollEnabled;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            return scrollEnabled && super.onTouchEvent(ev);
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return scrollEnabled && super.onInterceptTouchEvent(ev);
        }
    }

    // Cách 3: Vô hiệu hóa tạm thời khi đang scroll programmatically
    public void smoothScrollAndDisable(int x, int y) {
        scrollView.post(() -> {
            // Disable trước khi smooth scroll
            isScrollEnabled = false;
            scrollView.smoothScrollTo(x, y);
            
            // Re-enable sau khi scroll xong (cần OnScrollChangeListener API 23+)
            scrollView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
                if (!v.canScrollVertically(1) && !v.canScrollVertically(-1)) {
                    isScrollEnabled = true;
                    v.setOnScrollChangeListener(null);
                }
            });
        });
    }
}

Giải thích 3 cách:

Bước 4: Sử dụng Custom LockableScrollView trong XML

<app.com.sample.MainActivity.LockableScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout ...> ... </LinearLayout>

</app.com.sample.MainActivity.LockableScrollView>

Trong code: ((LockableScrollView) findViewById(R.id.scrollView)).setScrollingEnabled(false);

Bước 5: Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

Chạy ứng dụng

Chạy app, ScrollView cuộn bình thường. Nếu uncomment code demo, sau 3 giây ScrollView sẽ bị khóa (không cuộn được).

Cách vô hiệu hóa (disable) ScrollView bằng code trong Android

Mở rộng: Disable NestedScrollView / RecyclerView

// NestedScrollView
nestedScrollView.setOnTouchListener((v, event) -> !scrollEnabled);

// RecyclerView
recyclerView.setLayoutFrozen(true); // API 11+ - freeze layout, không scroll
// Hoặc
recyclerView.setNestedScrollingEnabled(false); // Tắt nested scroll
// Hoặc custom RecyclerView override onTouchEvent/onInterceptTouchEvent

Lưu ý

  • ScrollView chỉ scroll dọc. HorizontalScrollView cho scroll ngang
  • Vô hiệu hóa scroll không ẩn scrollbar - dùng android:scrollbars="none" hoặc setVerticalScrollBarEnabled(false)
  • Cân nhắc UX: User có thể bối rối nếu scroll bị khóa không có lý do rõ ràng
CáchMô tảƯu điểmNhược điểm
OnTouchListener return trueChặn touch event ở view chaĐơn giản, không cần custom classChặn cả click vào child view
Custom LockableScrollViewOverride onTouchEvent & onInterceptTouchEventTái sử dụng, kiểm soát tốt, không chặn click childCần dùng custom view trong XML
setOnScrollChangeListenerAPI 23+, detect khi scroll kết thúcCho phép scroll bằng code nhưng chặn userChỉ API 23+