54

我正在使用设计库提供的新类:TabLayout。而且我希望在特定情况下,我正在使用的那个不能再更改选项卡。

我设法在其查看器上禁用滑动,但我不知道如何通过单击选项卡来禁用页面更改。

提前致谢。

4

13 回答 13

107

我遇到了同样的问题,我用以下代码解决了它禁用标签上的触摸事件:

  LinearLayout tabStrip = ((LinearLayout)mTabLayout.getChildAt(0));
    for(int i = 0; i < tabStrip.getChildCount(); i++) {
        tabStrip.getChildAt(i).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return true;
            }
        });
    }
于 2015-08-19T20:24:01.783 回答
42

我找到了一个类似的答案,它更简单一些,如果您愿意,还允许您稍后重新启用选项卡,而无需处理覆盖 onTouch 事件。

TabLayout tabLayout = (TabLayout)  mParentView.findViewById(R.id.my_tabs);

LinearLayout tabStrip = ((LinearLayout)tabLayout.getChildAt(0));
tabStrip.setEnabled(false);
for(int i = 0; i < tabStrip.getChildCount(); i++) {
    tabStrip.getChildAt(i).setClickable(false);
}

如果您想重新启用选项卡,只需将子元素的 tabStrip.setEnabled 和 setClickable 设置为 true

LinearLayout tabStrip = ((LinearLayout)tabLayout.getChildAt(0));
tabStrip.setEnabled(true);
for(int i = 0; i < tabStrip.getChildCount(); i++) {
    tabStrip.getChildAt(i).setClickable(true);
}
于 2016-02-01T04:34:21.157 回答
21

与 pat8719 的答案非常相似,但仅禁用选项卡就足以防止它们被选中。

TabLayout tabLayout = (TabLayout)  mParentView.findViewById(R.id.my_tabs);
TabLayoutUtils.enableTabs( tabLayout, false );

TabLayoutUtils 类

public class TabLayoutUtils {

    public static void enableTabs(TabLayout tabLayout, Boolean enable){
        ViewGroup viewGroup = getTabViewGroup(tabLayout);
        if (viewGroup != null)
            for (int childIndex = 0; childIndex < viewGroup.getChildCount(); childIndex++)
            {
                View tabView = viewGroup.getChildAt(childIndex);
                if ( tabView != null)
                    tabView.setEnabled(enable);
            }
    }

    public static View getTabView(TabLayout tabLayout, int position){
        View tabView = null;
        ViewGroup viewGroup = getTabViewGroup(tabLayout);
        if (viewGroup != null && viewGroup.getChildCount() > position)
            tabView = viewGroup.getChildAt(position);

        return tabView;
    }

    private static ViewGroup getTabViewGroup(TabLayout tabLayout){
        ViewGroup viewGroup = null;

        if (tabLayout != null && tabLayout.getChildCount() > 0 ) {
            View view = tabLayout.getChildAt(0);
            if (view != null && view instanceof ViewGroup)
                viewGroup = (ViewGroup) view;
        }
        return viewGroup;
    }

}
于 2016-05-13T02:45:30.050 回答
18

对我来说,工作方法是这样的:

bool condition = ...
foreach (var view in _tabLayout.Touchables)
    view.Clickable = condition;

这是 100% 安全的,因为从 API 1 开始就支持getTouchables()调用。无需手动遍历布局或其他东西。我认为它比接受的答案要简单得多,但前提是所有选项卡都必须标记为不可点击。

PS:示例在 C# 上,因为我正在使用 Xamarin,但是将其转换回 Java 相当容易。享受!=)

科特林示例:

tabLayout.touchables.forEach { it.isClickable = false }

Java 示例:

for (View v: tabLayout.getTouchables())
    v.setClickable(false);
于 2018-02-22T15:42:35.760 回答
13

您可以使用的一个好技巧:

创建一个框架布局,覆盖要防止点击的视图,如下所示:

<FrameLayout
    android:clickable="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

此代码将在您的视图之上创建并清空/透明视图。android:clickable="true" 将拦截点击并阻止点击通过视图!

这个 hack 可能可以优化,但它的几行代码可以同时保护多个视图!

于 2016-06-06T13:20:55.037 回答
5

如果您为 Tab 使用自定义视图,如果您不想查看 ViewGroups,则可以使用 View#getParent() 获取对 Tab 的 View 的引用。

注意:使用自定义视图本身而不是父视图可能不起作用,因为它可以有边距,允许用户单击空白区域并仍然更改选项卡。

View tabView = (View) tab.getCustomView().getParent();

tabView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }
});

//or

tabView.setEnabled(false);

OnTouchListener 方式和 setEnabled() 方式做不同的事情,但具有相同的效果。我更喜欢单线。

同样,这仅在您使用自定义视图时才有效,否则 getParent() 调用将导致 NullPointerException。

于 2017-06-16T00:16:17.473 回答
4

还可以通过扩展 TabLayout 类并拦截所有触摸事件来避免子点击。

class NonTouchableTabLayout : TabLayout {

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        return true
    }
}

如果您想再次启用点击,只需在 onInterceptTouchEvent 方法上返回 false。

于 2019-04-30T11:38:02.520 回答
1

根据 Michele 的 Accepted Answer,禁用单击Kotlin中的单个选项卡

在包含选项卡的活动内部:

val tabs: TabLayout = findViewById(R.id.tabs)
...

(tabs.getChildAt(0) as LinearLayout).getChildAt(desiredTabPositionHere).isClickable = false

在片段(标签)内部:

(requireActivity().tabs.getChildAt(0) as LinearLayout).getChildAt(desiredTabPositionHere).isClickable = false

您可以打开和关闭点击功能(通过设置truefalse)。使用相同的方法,也可以修改visibilityalphabackgroundColor等。

于 2020-03-08T00:49:56.530 回答
1

在我的用例中,如果用户在选项卡中并按下其中一个按钮,则会启动计算,并且我不希望用户在计算完成之前能够切换选项卡。所以我使用了 Vladislav Rishe 的答案,但做了如下修改......

JAVA中:

//'tabLayout' is the variable where you reference your tab layout...
//A container to save the tabs that were disabled
private ArrayList<View> touchablesToRestore = new ArrayList<View>();

public void enableTabs() {
    for(View v: touchablesToRestore){
        v.setClickable(true);
    }
    //After you enable them all, clear the container
    touchablesToRestore.clear();
}

public void disableTabs(){
    for(View v: tabLayout.getTouchables()){
        //Add the tab that is being disabled to the container
        touchablesToRestore.add(v);
        v.setClickable(false);
    }
}

所以当用户点击按钮进行计算时,就在调用计算逻辑之前,我调用disableTabs(),然后一旦计算完成并显示出来,我调用enableTabs()...

于 2020-10-17T02:11:41.427 回答
0

基于这个优秀的解决方案,如果有人在 Kotlin 中需要它:

  val tabStrip = mTabLayout.getChildAt(0) as LinearLayout
    for (i in 0..tabStrip.childCount) {
        tabStrip.getChildAt(i).setOnTouchListener(object : View.OnTouchListener{
            override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
                return true
            }
        })
    }

或者更优雅的 lambda 解决方案

mTabLayout.setOnTouchListener {v: View, m: MotionEvent ->
        true
 }
于 2019-05-15T13:02:45.407 回答
0

ViewPager 的综合解决方案可防止在选项卡之间滑动,TabLayout 可防止在禁用时单击选项卡。

首先创建了 CustomViewPager 和 CustomTabLayout 类(继承 ViewPager 和 TabLayout 基类的功能)

// content of CustomViewPager.java
package mypackage;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.viewpager.widget.ViewPager;

public class CustomViewPager extends ViewPager {

    private boolean enableSwipe;

    public CustomViewPager(Context context) {
        super(context);
        init();
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        enableSwipe = true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return enableSwipe && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return enableSwipe && super.onTouchEvent(event);
    }

    public void setEnableSwipe(boolean enableSwipe) {
        this.enableSwipe = enableSwipe; 
    }
}

// content of CustomTabLayout.java
package mypackage;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.google.android.material.tabs.TabLayout;

public class CustomTabLayout extends TabLayout {
    private boolean enableTabs;

    public CustomTabLayout(Context context) {
        super(context);
        init();
    }

    public CustomTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        enableTabs = true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return !enableTabs;
    }

    public void setEnableTabs(boolean enable) {
        this.enableTabs = enable;
    }
}

创建用户界面:

        <mypackage.CustomTabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary" />

        <mypackage.CustomViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="100dp"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

在 onCreate 创建两个控件之间的关系:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        CustomViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(sectionsPagerAdapter);
        CustomTabLayout tabs = findViewById(R.id.tabs);
        tabs.setupWithViewPager(viewPager);
    }

EnableControls 函数启用/禁用选项卡:

private void EnableControls(boolean b) {
        CustomViewPager viewPager = findViewById(R.id.view_pager);
        CustomTabLayout tabs = findViewById(R.id.tabs);

        viewPager.setEnableSwipe(b);
        tabs.setEnableTabs(b);
}
于 2022-02-13T12:56:10.090 回答
0

在此处查看我的答案Disable Tabs in TabLayout

您可以 for 循环选项卡并使用此功能禁用所有选项卡

于 2018-12-19T13:48:09.210 回答
0

我们可以禁用和重新启用所有选项卡,如下所示:

科特林

禁用所有选项卡

fun disableAllTabs() {
    (binding.tlCommentTabs.getChildAt(0) as? ViewGroup)?.forEach { it.isEnabled = false }
    (binding.tlCommentTabs.getChildAt(1) as? ViewGroup)?.forEach { it.isEnabled = false }
}

启用所有选项卡

fun enableAllTabs() {
    (binding.tlCommentTabs.getChildAt(0) as? ViewGroup)?.forEach { it.isEnabled = true }
    (binding.tlCommentTabs.getChildAt(1) as? ViewGroup)?.forEach { it.isEnabled = true }
}

其中, binding.tlCommentTabs是 TabLayout 的一个实例。我正在使用视图绑定。无需在层次结构中添加额外的包装器视图。

于 2022-01-10T05:35:17.900 回答