【问题标题】:Disable TabLayout禁用选项卡布局
【发布时间】:2015-10-20 13:38:25
【问题描述】:

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

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

提前致谢。

【问题讨论】:

  • 你是如何禁用滑动的?
  • 您需要在他的 ViewPager 上禁用滑动。我把你送到这个帖子:stackoverflow.com/questions/9650265/…
  • @Shargotth 你是如何禁用滑动的??
  • 看上面的评论。如果您不理解链接中的解决方案,我可以尝试用其他语言来解释。
  • int tabPositionToDisable=1;线性布局 tabStrip = ((LinearLayout)tablayout.getChildAt(0)); tabStrip.getChildAt(tabPositionToDisable).setClickable(false); tabStrip.getChildAt(tabPositionToDisable).setEnabled(false);

标签: android disabled-control android-tablayout


【解决方案1】:

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

  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;
            }
        });
    }

【讨论】:

  • 也适合我。谢谢!
  • 我在onCreateView 中调用这些行但不工作:/
  • 这很好用,但安全吗?有没有可能失败的情况?
  • @harsh_v 这在未来可能会失败,因为 Google 在 Android 的每个主要版本中都弃用了更多这样的反射使用。除此之外,多年来在高使用率的生产应用中证明它对我来说是安全的。
【解决方案2】:

我找到了一个类似的答案,它更简单一些,如果您愿意,还允许您稍后重新启用选项卡,而无需处理覆盖 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);
}

【讨论】:

  • @user1269737 你能说的更具体一些吗?我想解决这个问题,你说的指标是什么意思
  • 有文本和指示符(文本下方的行)。该指示器仍然可以点击。
  • @user1269737 感谢您指出这一点,我会更新我的答案,因为我经常使用它
  • 这个答案只是禁用触摸,但通过滚动用户可以转到禁用标签,所以它不好。
【解决方案3】:

与 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;
    }

}

【讨论】:

    【解决方案4】:

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

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

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

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

    Kotlin 示例:

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

    Java 示例:

    for (View v: tabLayout.getTouchables())
        v.setClickable(false);
    

    【讨论】:

    • 这就是我所做的。我还降低了视图上的 alpha 值,以直观地显示选项卡的禁用/启用状态。
    • 值得注意的是,这有利于禁用,但无法重新启用。这是因为一旦将视图设置为不可点击,getTouchables() 将不再返回它。我以为您可以在第一次通话或其他事情后存储视图,但是如果您期望层次结构发生变化,那将变得很危险。
    • 我想切换它。我无法打开可点击。
    • 非常适合禁用可点击效果,这正是我所需要的......但是如果你想重新打开它就不起作用
    【解决方案5】:

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

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

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

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

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

    【讨论】:

    • 这可能是一个“黑客”,但在 IMO,它是一种比其他答案更好的方法,这取决于 TabLayout 内部实现的细节。我需要在整个应用程序上创建一个“介绍”叠加层,并在它运行时禁用它下面的所有内容,所以这是一个简单而有效的灵丹妙药。
    • 有史以来最好的解决方案
    【解决方案6】:

    如果您为 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。

    【讨论】:

      【解决方案7】:

      还可以通过扩展 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。

      【讨论】:

      • 这是 imo 最干净的解决方案。其他依赖 TabLayout 内部结构的答案让我担心可能非常脆弱。我对其进行了一些更改并实现了override fun onInterceptTouchEvent(event: MotionEvent): Boolean { return !isEnabled } 所以当我设置tabLayout.isEnabled = false 它会停止点击事件
      【解决方案8】:

      根据 Michele 接受的答案,在 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

      【讨论】:

        【解决方案9】:

        在我的用例中,如果用户在选项卡中并按下其中一个按钮,则会启动计算,并且我不希望用户在计算完成之前能够切换选项卡。所以我使用了 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()...

        【讨论】:

          【解决方案10】:

          在这里查看我的答案Disable Tabs in TabLayout

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

          【讨论】:

            【解决方案11】:

            基于这个优秀的解决方案,如果有人在 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
             }
            

            【讨论】:

            • 你的 kotlin 代码有错误。在 tabStrip.childCount 之前应该是 i 在 0 中。使用 .. 你期望一个包含范围,这不是你想要的。它会崩溃。
            【解决方案12】:

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

            科特林

            禁用所有标签

            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 的一个实例。我正在使用视图绑定。无需在层次结构中添加额外的包装器视图。

            【讨论】:

              【解决方案13】:

              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);
              }
              

              【讨论】:

                猜你喜欢
                • 2016-06-12
                • 1970-01-01
                • 2015-11-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-04-19
                • 2015-10-28
                相关资源
                最近更新 更多