禁用 TabLayout
Disable TabLayout
我正在使用设计库提供的新 class:TabLayout。我希望在特定情况下,我正在使用的那个不能再更改标签。
我设法禁用了其 viewpager 上的滑动,但我不知道如何通过单击选项卡来禁用页面更改。
提前致谢。
我遇到了同样的问题,我使用以下代码解决了禁用选项卡上的触摸事件的问题:
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;
}
});
}
我找到了一个更简单的类似答案,如果您愿意,还可以稍后重新启用选项卡,而不必处理重写 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);
}
与 pat8719 的回答非常相似,但仅禁用选项卡就足以防止它们被选中。
TabLayout tabLayout = (TabLayout) mParentView.findViewById(R.id.my_tabs);
TabLayoutUtils.enableTabs( tabLayout, false );
TabLayoutUtils class
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;
}
}
你可以使用的一个好技巧:
创建一个框架布局来覆盖您想要防止点击的视图,如下所示:
<FrameLayout
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
此代码将在您的视图之上创建并 empty/transparent 视图。
android:clickable="true" 将拦截点击并阻止点击通过视图!
这个 hack 可能可以优化,但它的几行代码可以同时保护多个视图!
如果您为选项卡使用自定义视图,并且不想浏览 ViewGroup,则可以使用 View#getParent() 获取对选项卡视图的引用。
注意:使用自定义视图本身而不是父视图可能不起作用,因为它可以有边距,允许用户单击空白 space 并仍然更改选项卡。
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。
对我来说,工作方法是这样的:
bool condition = ...
foreach (var view in _tabLayout.Touchables)
view.Clickable = condition;
这是 100% 安全的,因为 getTouchables() 自 API 以来支持调用 1. 无需手动遍历布局或其他内容。我认为它比接受的答案简单得多,但前提是所有选项卡都必须标记为不可点击。
P.S.: 示例在 C# 上,因为我正在使用 Xamarin,但将它转换回 Java 相当容易。享受! =)
Kotlin 示例:
tabLayout.touchables.forEach { it.isClickable = false }
Java 示例:
for (View v: tabLayout.getTouchables())
v.setClickable(false);
在这里查看我的回答
您可以for循环选项卡并使用此功能禁用所有选项卡
也可以通过扩展 TabLayout class 并拦截所有触摸事件来避免儿童点击。
class NonTouchableTabLayout : TabLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return true
}
}
如果您想再次启用点击,只需 return onInterceptTouchEvent 方法上的 false。
基于这个优秀的解决方案,如果有人在 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
}
根据 Michele 接受的答案,在 Kotlin 中禁止单击 单个选项卡:
标签内包含 activity:
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
您可以打开和关闭点击功能(通过设置true
或false
)。同样的方法,也可以修改visibility、alpha、backgroundColor等
在我的用例中,如果用户在选项卡中并按下其中一个按钮,则会启动计算,我不希望用户在计算完成之前能够切换选项卡。所以我使用了 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()
...
我们可以禁用和重新启用所有选项卡,如下所示:
Kotlin
禁用所有标签
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 的一个实例。我正在使用视图绑定。无需在层次结构中添加额外的包装器视图。
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;
}
}
创建 UI:
<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 函数到 enable/disable 选项卡:
private void EnableControls(boolean b) {
CustomViewPager viewPager = findViewById(R.id.view_pager);
CustomTabLayout tabs = findViewById(R.id.tabs);
viewPager.setEnableSwipe(b);
tabs.setEnableTabs(b);
}
我正在使用设计库提供的新 class:TabLayout。我希望在特定情况下,我正在使用的那个不能再更改标签。
我设法禁用了其 viewpager 上的滑动,但我不知道如何通过单击选项卡来禁用页面更改。
提前致谢。
我遇到了同样的问题,我使用以下代码解决了禁用选项卡上的触摸事件的问题:
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;
}
});
}
我找到了一个更简单的类似答案,如果您愿意,还可以稍后重新启用选项卡,而不必处理重写 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);
}
与 pat8719 的回答非常相似,但仅禁用选项卡就足以防止它们被选中。
TabLayout tabLayout = (TabLayout) mParentView.findViewById(R.id.my_tabs);
TabLayoutUtils.enableTabs( tabLayout, false );
TabLayoutUtils class
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;
}
}
你可以使用的一个好技巧:
创建一个框架布局来覆盖您想要防止点击的视图,如下所示:
<FrameLayout
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
此代码将在您的视图之上创建并 empty/transparent 视图。 android:clickable="true" 将拦截点击并阻止点击通过视图!
这个 hack 可能可以优化,但它的几行代码可以同时保护多个视图!
如果您为选项卡使用自定义视图,并且不想浏览 ViewGroup,则可以使用 View#getParent() 获取对选项卡视图的引用。
注意:使用自定义视图本身而不是父视图可能不起作用,因为它可以有边距,允许用户单击空白 space 并仍然更改选项卡。
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。
对我来说,工作方法是这样的:
bool condition = ...
foreach (var view in _tabLayout.Touchables)
view.Clickable = condition;
这是 100% 安全的,因为 getTouchables() 自 API 以来支持调用 1. 无需手动遍历布局或其他内容。我认为它比接受的答案简单得多,但前提是所有选项卡都必须标记为不可点击。
P.S.: 示例在 C# 上,因为我正在使用 Xamarin,但将它转换回 Java 相当容易。享受! =)
Kotlin 示例:
tabLayout.touchables.forEach { it.isClickable = false }
Java 示例:
for (View v: tabLayout.getTouchables())
v.setClickable(false);
在这里查看我的回答
您可以for循环选项卡并使用此功能禁用所有选项卡
也可以通过扩展 TabLayout class 并拦截所有触摸事件来避免儿童点击。
class NonTouchableTabLayout : TabLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return true
}
}
如果您想再次启用点击,只需 return onInterceptTouchEvent 方法上的 false。
基于这个优秀的解决方案,如果有人在 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
}
根据 Michele 接受的答案,在 Kotlin 中禁止单击 单个选项卡:
标签内包含 activity:
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
您可以打开和关闭点击功能(通过设置true
或false
)。同样的方法,也可以修改visibility、alpha、backgroundColor等
在我的用例中,如果用户在选项卡中并按下其中一个按钮,则会启动计算,我不希望用户在计算完成之前能够切换选项卡。所以我使用了 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()
...
我们可以禁用和重新启用所有选项卡,如下所示:
Kotlin
禁用所有标签
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 的一个实例。我正在使用视图绑定。无需在层次结构中添加额外的包装器视图。
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;
}
}
创建 UI:
<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 函数到 enable/disable 选项卡:
private void EnableControls(boolean b) {
CustomViewPager viewPager = findViewById(R.id.view_pager);
CustomTabLayout tabs = findViewById(R.id.tabs);
viewPager.setEnableSwipe(b);
tabs.setEnableTabs(b);
}