Есть отключенный onClick?

Я хочу иметь возможность реагировать на нажатие на отключенном переключателе, возможно ли это?

У меня есть переключатель, который не включен, пока пользователь не заполнит некоторую информацию, поэтому он выглядит так:

введите описание изображения здесь

Я хочу предложить пользователю заполнить информацию, если он нажмет на отключенный переключатель в диалоговом окне, например:

 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() не срабатывает, когда я нажимаю на отключенный переключатель, так как мне получить, когда пользователь нажимает на него?


person Ruchir Baronia    schedule 07.08.2016    source источник
comment
Что такое lightSwitch? Обновляется ли его метод isEnabled() автоматически, или вам нужно обновить его самостоятельно (например, lightSwitch.setEnabled(!lightSwitch.isEnabled())?   -  person mapeters    schedule 18.08.2016
comment
Кроме того, что такое mySwitch? Пожалуйста, включите объявления для ваших переменных.   -  person mapeters    schedule 18.08.2016
comment
любой ответ ? ты проверял мой код?   -  person Elltz    schedule 24.08.2016


Ответы (10)


Вы можете поместить прозрачный View поверх Switch и переключить его включенное состояние напротив переключателя и показать сообщение при нажатии этого наложенного View.

person Karakuri    schedule 08.08.2016

Из ссылки 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 потребляются, но не передаются слушателям, тем самым обходя весь ваш возможный код. Таким образом, невозможно прослушивать события в отключенном представлении.

Тем не менее, ваши варианты,

  1. Измените стиль, чтобы он имитировал стиль отключенного представления, как указано здесь, а затем добавьте необходимые функции.
  2. Добавьте невидимый вид наложения для выполнения необходимых функций, для которых вы можете установить значение «Исчез», как только представление должно быть включено.
  3. Используйте что-то кроме включенного (вы можете setClickable(false) и использовать сенсорные события)
person Droidekas    schedule 18.08.2016
comment
я выбрал вариант 2, так что мне не нужно было стилизовать все различные элементы управления, которые мне нужно было отключить... я использовал относительный макет, чтобы я мог поместить наложение поверх других элементов управления. этот ответ помог мне создать наложение.... stackoverflow.com/a/33997626/2898715 - person Eric; 19.01.2019

Вы можете установить 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; 
            }
        });
person Nir Duan    schedule 21.08.2016

Когда он отключен, setEnabled(false), эти слушатели не будут работать.

Попробуйте так: не отключайте его, используйте setOnCheckedChangeListener и проверьте, заполнено ли ваше поле:

использовать setOnCheckedChangeListener

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

это перепроверит его обратно и выведет предупреждение, пока не будет выполнено isEntryFilled.

ИЗМЕНИТЬ

ИЛИ вместо setEnabled(false) используйте setClickable(false) или android:clickable="false", поскольку в документах говорится, что setClickable() связано с событиями кликов.

и вместо OnClickListener попробуйте OnTouchListener. Он зарегистрирует ваше касание вниз (и проигнорирует касание вверх), поскольку щелчок состоит из нажатия вниз+вверх.

    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)

person TWL    schedule 07.08.2016
comment
Нет, onCheckedChanged() вызывается только в том случае, если переключатель включен, а в данном случае - нет. - person Ruchir Baronia; 08.08.2016
comment
Когда он отключен, setEnabled(false), эти слушатели не будут работать, попробуйте другое мое предложение. - person TWL; 08.08.2016
comment
Я знал о возможности просто снять отметку в onCheckChanged, если это необходимо, но мой вопрос заключается в том, могу ли я специально обнаружить щелчок по отключенному элементу. Если это невозможно, мне, возможно, придется прибегнуть к этому другому методу, но я уверен, что есть способ узнать, нажал ли пользователь отключенный переключатель. - person Ruchir Baronia; 08.08.2016
comment
disabled отключит все прослушиватели событий, но... попробуйте мое новое предложение - person TWL; 08.08.2016

Попробуйте установить setFocusable(false) и setEnabled(true) на коммутаторе. Таким образом, события щелчка будут запускаться, пока переключатель все еще «отключен». Взято из этого ответа.

person Manuel Allenspach    schedule 18.08.2016

Пусть Родитель View перехватит 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_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="70dp"
android:background="#273746">   

<FrameLayout
    android:layout_width="match_parent"        
    android:id="@+id/ass"
    android:background="@drawable/abc_popup_background_mtrl_mult"
    android:layout_height="match_parent">
</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

person Elltz    schedule 20.08.2016
comment
не работает, если отключен другой способ попросить у меня фрагмент? если да, вы можете спросить @RuchirBaronia - person Elltz; 20.08.2016
comment
проверь мое редактирование, братан, и дай мне знать, если это полезно @RuchirBaronia - person Elltz; 21.08.2016

Установите переключатели отключения на прослушивателе кликов, чтобы изменить прослушиватели других переключателей. Например:

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();
                        }
                    }
             });
      }
}
person Nick    schedule 23.08.2016

Я предполагаю, что вы отключили переключатель с помощью 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();
            }
        }
    });
person Pirdad Sakhizada    schedule 23.08.2016

Вы можете сделать это по-другому, дайте корневой макет для кнопки переключения с той же шириной и высотой кнопки переключения.

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

</RelativeLayout>

Когда вы отключаете кнопку, сделайте кнопку недоступной для фокусировки и кликабельной. Затем ОС передаст сенсорную функциональность в rootlayout. В корневом листере кликов мы можем написать логику кликов, когда кнопка не включена.

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);
person Jinesh Francis    schedule 24.08.2016

person    schedule
comment
OnClickListerns не работают, если переключатель отключен, вот о чем мой вопрос, как я могу увидеть, нажат ли отключенный переключатель? - person Ruchir Baronia; 20.08.2016
comment
не отключайте переключатель, включите его и примените этот код. - person Nikhil Borad; 22.08.2016
comment
нет, все дело в том, чтобы оставить его отключенным и найти обходной путь - person Ruchir Baronia; 23.08.2016