有一个禁用的onClick?

Posted

技术标签:

【中文标题】有一个禁用的onClick?【英文标题】:Have a disabled onClick? 【发布时间】:2016-12-13 14:38:46 【问题描述】:

我希望能够响应禁用开关上的点击事件,这可能吗?

我有一个开关直到用户填写一些信息才启用,所以它看起来像这样:

如果用户单击禁用的开关并带有对话框,我想提示用户填写信息,如下所示:

 mySwitch.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 

            if (!userInfo.isFilled)
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle("Fill out info first!")
                        .setMessage("You must first fill out info before turning on this featurel")
                        .setNeutralButton("Okay", null)
                        .show();
            
        
    );

但是,onClick()在我点击禁用的开关时并没有被触发,那么当用户点击它时我该如何获取呢?

【问题讨论】:

什么是lightSwitch?它的isEnabled() 方法是自动更新的,还是需要您自己更新(即lightSwitch.setEnabled(!lightSwitch.isEnabled()) 另外,mySwitch 是什么?请包含变量的声明。 任何回应?你检查我的代码了吗? 【参考方案1】:

您可以在Switch 上放置一个透明的View,并在开关对面切换其启用状态,并在单击此覆盖的View 时显示消息。

【讨论】:

【参考方案2】:

来自View.java源代码,

public boolean dispatchTouchEvent(MotionEvent event) 
    // If the event should be handled by accessibility focus first.
    if (event.isTargetAccessibilityFocus()) 
        // We don't have focus or no virtual descendant has it, do not handle the event.
        if (!isAccessibilityFocusedViewOrHost()) 
            return false;
        
        // We have focus and got the event, then use normal event dispatch.
        event.setTargetAccessibilityFocus(false);
    

    boolean result = false;

    if (mInputEventConsistencyVerifier != null) 
        mInputEventConsistencyVerifier.onTouchEvent(event, 0);
    

    final int actionMasked = event.getActionMasked();
    if (actionMasked == MotionEvent.ACTION_DOWN) 
        // Defensive cleanup for new gesture
        stopNestedScroll();
    

    if (onFilterTouchEventForSecurity(event)) 
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) 
            result = true;
        

        if (!result && onTouchEvent(event)) 
            result = true;
        
    

    if (!result && mInputEventConsistencyVerifier != null) 
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
    

    // Clean up after nested scrolls if this is the end of a gesture;
    // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
    // of the gesture.
    if (actionMasked == MotionEvent.ACTION_UP ||
            actionMasked == MotionEvent.ACTION_CANCEL ||
            (actionMasked == MotionEvent.ACTION_DOWN && !result)) 
        stopNestedScroll();
    

    return result;

启用标志确保 UnhandledEvents 被消耗但不传递给侦听器,从而绕过所有可能的代码。因此无法在禁用视图上侦听事件。

也就是说,您的选择是,

    更改样式以模仿here 中提到的禁用视图的样式,然后添加所需的功能。 添加一个覆盖不可见视图以执行您需要的功能,一旦启用该视图,您可以将其设置为 Gone。 使用除了启用之外的东西,(你可以setClickable(false) 并使用触摸事件)

【讨论】:

我选择了选项 2,因此我不需要设置我需要禁用的所有不同控件的样式...我使用了相对布局,以便我可以将叠加层放在其他控件。这个答案帮助我创建了一个覆盖......***.com/a/33997626/2898715【参考方案3】:

您可以设置onTouchListener 并针对用户之前的操作对boolean(例如isToggleEnable)参考做出反应:

 mySwitch.setOnTouchListener(new View.OnTouchListener() 
            @Override
            public boolean onTouch(View v, MotionEvent event) 
                if(!isToggleEnable)
                //Taost here
                
                //If isToggleEnable = false on return OnClickListener won't be called
                return isToggleEnable; 
            
        );

【讨论】:

【参考方案4】:

当它被禁用时,setEnabled(false),这些监听器将无法工作。

试试这个方法:不要禁用它,使用 setOnCheckedChangeListener 并检查你的 is-entry-fill 在那里:

使用setOnCheckedChangeListener

    switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() 
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
            if (!isEntryFilled) 
                buttonView.setChecked(false);
                // your alert dialog
             else 
            
        
    );

这将重新检查它以关闭并弹出您的警报,直到遇到isEntryFilled

编辑

或者使用setClickable(false)android:clickable="false" 代替setEnabled(false),因为文档说setClickable()点击事件 相关联。

而不是OnClickListener,试试OnTouchListener。它将注册您的 on-down-touch(并忽略您的 on-up-touch),因为点击由 down+up 组成。

    switch.setOnTouchListener(new View.OnTouchListener() 
        @Override
        public boolean onTouch(View v, MotionEvent event) 
            if (!isEntryFilled) 
                buttonView.setChecked(false);
                // your alert dialog
            
            return false;
        
    );

然后在其他地方检查isEntryFilled,使用switch.setClickable(true) 重新激活您的开关

【讨论】:

不,onCheckedChanged() 仅在启用开关时调用,在这种情况下不是。 当它被禁用时,setEnabled(false),这些监听器将不起作用,试试我的其他建议。 我知道如果需要可以在 onCheckChanged 中取消选中它的选项,但我的问题是我是否可以专门检测对禁用项目的点击。如果不可能,我可能需要求助于其他方法,但我确信有办法找出用户是否点击了禁用的开关。 disabled 将禁用所有事件监听器,但是...试试我的新建议【参考方案5】:

尝试在您的交换机上设置setFocusable(false)setEnabled(true)。这样,当开关仍被“禁用”时,点击事件将被触发。取自this answer。

【讨论】:

【参考方案6】:
mySwitch.setOnClickListener(new View.OnClickListener() 
         @Override
         public void onClick(View v) 
                if (isClick())
                   //Your Valid Code
                else
                  //Make our switch to false
                  new AlertDialog.Builder(MainActivity.this)
                           .setTitle("Fill out info first!")
                           .setMessage("You must first fill out info before turning on this featurel")
                            .setNeutralButton("Okay", null)
                            .show();
                   
                
);

    public Boolean isClick()
         //check condition that user fill details or not
         //if yes then return true
         // else return false
    

【讨论】:

如果开关被禁用,OnClickListerns 不起作用,这就是我的问题,如何查看禁用的开关是否被点击? 不要禁用开关,让它启用并应用此代码。 不,重点是保持禁用它并找到解决方法【参考方案7】:

让ParentView拦截ClickEvents或TouchEvents,当它检测到接收View是否被禁用时,做你必须做的事情。

编辑

禁用时不起作用?

试试这些代码,我使用LinearLayout 方便对齐。但总的来说它应该给你一个例子

这是一个完整的例子

XML

<FrameLayout 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:layout_
android:layout_
android:layout_marginTop="70dp"
android:background="#273746">   

<FrameLayout
    android:layout_        
    android:id="@+id/ass"
    android:background="@drawable/abc_popup_background_mtrl_mult"
    android:layout_>
</FrameLayout>

MainActivity onCreate

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_entry_screen);
    FrameLayout fl = (FrameLayout)findViewById(R.id.ass);
    Test t = new Test(this);
    FrameLayout.LayoutParams lp = (LayoutParams) fl.getLayoutParams();
    lp.height = LayoutParams.MATCH_PARENT;
    lp.width = LayoutParams.MATCH_PARENT;
    t.setOrientation(LinearLayout.VERTICAL);
    t.setLayoutParams(lp);
    fl.addView(t);
    t.setBackgroundColor(Color.YELLOW);
    Button b = new Button(this);
    b.setText("patricia");
    t.addView(b);
     b = new Button(this);
    b.setText("monica");
    t.addView(b);

    b = new Button(this);
    b.setText("rebecca");
    t.addView(b);


Test.java

public class Test extends LinearLayout 

public Test(Context context) 
    super(context);


@Override
public boolean onInterceptTouchEvent(MotionEvent event) 
    StringBuilder sb = new StringBuilder();
    sb.append("intercept \n\r");
    int x = (int)event.getX(),
            y= (int)event.getY();

    for(int i =0; i< getChildCount(); i++)
        int[] pos = new int[]getChildAt(i).getLeft(),getChildAt(i).getTop(),
                getChildAt(i).getMeasuredWidth(),
                getChildAt(i).getMeasuredHeight();

        sb.append(getChildAt(i).getLeft()+", ");
        sb.append(getChildAt(i).getTop()+", ");
        sb.append(getChildAt(i).getMeasuredWidth()+", ");
        sb.append(getChildAt(i).getMeasuredHeight());
        sb.append("\n\r");
        sb.append(isInBounds(pos, x, y));
        sb.append("\n\r");
    
    sb.append("x is ");
    sb.append(x);
    sb.append("y is ");
    sb.append(y);
    Toast.makeText(getContext(),sb.toString() , Toast.LENGTH_LONG).show();
    return super.onInterceptTouchEvent(event);


private boolean isInBounds(int[] dimen, int x, int y)
    return ((x >= dimen[0] && x < (dimen[0] + dimen[2]))
            && (y >= dimen[1] && y < (dimen[1] + dimen[3])));



现在,您单击的那个将检查为真,即孩子,现在当检查为真时,您可以执行类似的操作

View v = getchildAt(pos);
//its the one that is tapped or clicked
if(!v.isEnabled())
    //this is the guy you want now, do what you want to do

对于点击事件我不会尝试这个,但你可以做View.performClick() 或将你的对话框放在ViewGroup 类中并调用它

实际上你可以使用View..getClipBounds() 将自己从 int 数组中解救出来

【讨论】:

如果禁用另一种向我询问 sn-p 的方式不起作用?如果是的话,你可以问@RuchirBaronia 检查我的编辑兄弟,如果它有帮助请告诉我@RuchirBaronia【参考方案8】:

在点击监听器上设置禁用开关以更改其他开关的监听器。例如:

Switch s = (Switch) findViewById(R.id.SwitchID);

if (s != null) 
    s.setOnCheckedChangeListener(this);


/* ... */

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
    Toast.makeText(this, "The Switch is " + (isChecked ? "on" : "off"),
                   Toast.LENGTH_SHORT).show();
    if(isChecked) 
        //do stuff when Switch is ON
        //this is where you set your normal state OnClickListner
     else 
            mySwitch.setOnClickListener(new View.OnClickListener() 
                    @Override
                    public void onClick(View v) 

                        if (!userInfo.isFilled)
                            new AlertDialog.Builder(MainActivity.this)
                            .setTitle("Fill out info first!")
                            .setMessage("You must first fill out info before turning on this featurel")
                            .setNeutralButton("Okay", null)
                            .show();
                        
                    
             );
      

【讨论】:

【参考方案9】:

我猜你已经使用 switch.setEnabled(false) 禁用了开关。如果是这样,onclick 事件将不会触发。如果你还想在开关被禁用时处理点击动作,你可以使用 .setOnTouchListener()...

不过,最好的办法是使用 .setOnCheckedChangeListener() 并保持开关处于启用状态。基本上,当 onCheckChanged() 被调用时,如果开关值打开,您可以弹出对话框,当用户单击确定时,您默认将开关恢复为关闭。

    mSwitched.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() 

        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean checked) 

            if (checked && !userInfo.isFilled)
                new AlertDialog.Builder(Activity.this)
                        .setTitle("Fill out info first!")
                        .setMessage("You must first fill out info before turning on this featurel")
                        .setNeutralButton("Okay", new DialogInterface.OnClickListener() 

                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) 

                                mSwitched.setChecked(false);
                            
                        )
                        .show();
            
        
    );

【讨论】:

【参考方案10】:

你可以用不同的方式做到这一点,给一个根布局来切换按钮与切换按钮的宽度和高度相同

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    >
    <!--Root layout to toggle button with same height and width 
        of toggle button-->
   <LinearLayout
       android:layout_
       android:id="@+id/linear"
       android:layout_>
    <ToggleButton
        style="?android:attr/buttonStyleSmall"
        android:layout_
        android:layout_
        android:id="@+id/button"
         />
   </LinearLayout>

</RelativeLayout>

当你禁用按钮时,将按钮设为不可聚焦和可点击。然后操作系统会将触摸功能移交给rootlayout。在root layout click listner中我们可以编写按钮未启用时的点击逻辑

public class MainActivity extends AppCompatActivity 
    ToggleButton button;
    LinearLayout linearLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button= (ToggleButton) findViewById(R.id.button);
        linearLayout= (LinearLayout) findViewById(R.id.linear);
        //disabling button
        button.setEnabled(false);
        button.setClickable(false);
        button.setFocusableInTouchMode(false);
        button.setFocusable(false);
        button.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //write the logic here which will execute when button is enabled
            
        );
        linearLayout.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //write the logic here which will execute when button is disabled
            
        );
    


当您启用按钮时,使按钮可点击和可聚焦。

//enabling button
  button.setEnabled(true);
  button.setClickable(true);
  button.setFocusableInTouchMode(true);
  button.setFocusable(true);

【讨论】:

以上是关于有一个禁用的onClick?的主要内容,如果未能解决你的问题,请参考以下文章

使用 onclick 禁用文本输入

当设备视口大于指定大小时禁用onClick事件[重复]

如何启用禁用的文本框 onclick 使用角度的按钮

在 React 中禁用 DIV onClick 的最佳方法

如何禁用日期控制按钮的 FullCalendar onClick 功能?

Android - 禁用可扩展列表中一组的 onClick 突出显示?