You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何禁用Android应用所有视图的拖拽功能并保留指定特性?

问题描述

在Google Play Console的Errors and ANR区域,搭载Android 10及更高版本的用户设备频繁出现如下异常:

Exception java.lang.IllegalStateException: Drag shadow dimensions must
be positive at android.view.View.startDragAndDrop (View.java:25464)
at android.widget.Editor.startDragAndDrop (Editor.java:1183) at
android.widget.Editor.performLongClick (Editor.java:1209) at
android.widget.TextView.performLongClick (TextView.java:12292) at
android.view.View.performLongClick (View.java:7222) at
android.view.View$CheckForLongPress.run (View.java:27374) at
android.os.Handler.handleCallback (Handler.java:883) at
android.os.Handler.dispatchMessage (Handler.java:100) at
android.os.Looper.loop (Looper.java:241) at
android.app.ActivityThread.main (ActivityThread.java:7617) at
java.lang.reflect.Method.invoke at
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run
(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main
(ZygoteInit.java:941)

经排查,该异常由TextView触发拖拽操作导致,对应堆栈中的android.widget.TextView.performLongClick (TextView.java:12292)行。

需求说明

不需要拖拽(Drag and Drop)功能,但需保留TextView的以下特性:

  • 选择部分或全部文本进行复制、粘贴、分享;
  • 通过继承自TextView的自定义类ZoomTextView实现捏合缩放调整文本大小;
  • 支持可点击链接。
    此外,应用中使用的RecyclerView、菜单等视图也需要禁用拖拽功能,希望全局禁用应用内所有视图的拖拽功能。

现有代码

Fragment内TextView配置代码

public class MyFragment extends Fragment implements TextToSpeechCallback {

    private ZoomTextView mTextView;

    private void setConfiguration() {

        mViewModel =
                new ViewModelProvider(this).get(MyViewModel.class);
        mTextView = binding.include.tvZoomable;
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
        float fontSize = Float.parseFloat(prefs.getString("font_size", "18"));
        String fontFamily = String.format(new Locale("es"),"fonts/%s",prefs.getString("font_name", "robotoslab_regular.ttf"));
        Typeface tf= Typeface.createFromAsset(requireActivity().getAssets(),fontFamily);
        mTextView .setTypeface(tf);
        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
        hasInvitatory = prefs.getBoolean("invitatorio", false);
        isVoiceOn = prefs.getBoolean("voice", true);
        if (isVoiceOn) {
            sbReader = new StringBuilder(VOICE_INI);
        }
    }
    
    // ...

}

TextView的XML布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root_preferences"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".ui.activities.MainActivity"
    >

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.example.utils.ZoomTextView
                android:id="@+id/tv_Zoomable"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingTop="0dp"
                android:paddingBottom="50dp"
                style="@style/TextAppearance.AppTheme.DisplayBody"
                />
        </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

提问

是否可以通过XML或编程方式禁用应用内所有视图的拖拽功能?


解决方案

一、针对TextView的精准禁用(优先推荐)

异常由TextView长按触发拖拽导致,且需保留文本选择、缩放、链接点击功能,直接在自定义ZoomTextView中重写拖拽相关方法即可:

public class ZoomTextView extends TextView {
    // 已有构造方法和捏合缩放逻辑...

    @Override
    public boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags) {
        // 返回false阻止拖拽启动,不影响文本选择等功能
        return false;
    }

    // 兼容旧版本拖拽API
    @Override
    public boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags) {
        return false;
    }
}

此方式仅拦截TextView的拖拽触发,完全保留你需要的所有特性——文本选择、缩放、链接点击的逻辑与拖拽分离,不受影响。

二、全局禁用所有视图的拖拽功能

1. 自定义Application拦截全局视图

创建自定义Application类,通过LayoutInflater.Factory2拦截所有视图的拖拽逻辑:

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        LayoutInflater.from(this).setFactory2(new LayoutInflater.Factory2() {
            @Override
            public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
                View view = getDelegate().createView(parent, name, context, attrs);
                if (view != null) {
                    disableViewDrag(view);
                }
                return view;
            }

            @Override
            public View onCreateView(String name, Context context, AttributeSet attrs) {
                return onCreateView(null, name, context, attrs);
            }
        });
    }

    private void disableViewDrag(View view) {
        // 给TextView以外的视图设置长按监听,消费事件阻止拖拽
        if (!(view instanceof TextView)) {
            view.setOnLongClickListener(v -> true);
        }
        // 重写视图的拖拽方法做双重拦截
        try {
            Method method = View.class.getDeclaredMethod("startDragAndDrop", ClipData.class, DragShadowBuilder.class, Object.class, int.class);
            method.setAccessible(true);
            // 通过动态代理替换方法实现(可选,若仅拦截长按不够彻底时使用)
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

需在AndroidManifest.xml中指定自定义Application:

<application
    android:name=".MyApp"
    <!-- 其他配置 -->
    >
</application>

2. 全局样式设置(不推荐)

在全局主题中添加android:longClickable="false",但会导致TextView无法触发长按文本选择,不符合需求,仅适用于无长按需求的场景。

三、RecyclerView与菜单的拖拽禁用

  • RecyclerView:若通过ItemTouchHelper实现拖拽,直接移除对应的ItemTouchHelper.Callback即可;系统默认拖拽则给子项设置setOnLongClickListener(v -> true)。
  • 菜单:系统菜单默认无拖拽功能,若为自定义拖拽菜单,直接移除拖拽逻辑即可。

内容的提问来源于stack exchange,提问作者A. Cedano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:17:16