Как открыть счетчик одним щелчком мыши, когда открыт другой счетчик

У меня мало spinners в форме. Когда я нажимаю на любой из них, он открывается и показывает параметры. Когда я нажимаю на любой другой spinner, он закрывает открытый spinner, но затем мне нужно снова щелкнуть по желаемому spinner, чтобы открыть его.

Я хотел бы первым щелкнуть по 2-му счетчику, чтобы я мог закрыть первый открытый счетчик, а затем открыть щелчок.

Я видел сообщения о закрытии счетчика на любом клике снаружи, но этого недостаточно, потому что я все еще не знаю, что нажал желаемый счетчик (onclick() второго счетчика не запущен).

Ответы

Ответ 1

Я немного занят, чтобы писать и давать вам некоторый код, но получая помощь от таких ссылок, как , вы можете получить фрагмент. так вот моя идея. Сначала, когда вы создаете свое представление, выберите координату прядильщиков, например, spinner A, B и C. Также напишите функцию (например, foo(...)), которая возвращает координату щелкнутой точки , но не потребляет ее. Затем зарегистрируйте A, B и C onItemSelectedListeners, и в их тесте onNothingSelected проверьте, находится ли нажатая точка в других двух областях прядильщиков или нет (используя foo(...), который вы написали ранее). Таким образом, вы можете получить то, что хотите. Извините, что я занят и ленив, но это работает. Надеюсь, я помог вам.

Обновление (для получения штрихов):

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

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

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

Ответ 2

Вот пользовательский счетчик, который делает именно то, что вам нужно,

PopUpActionspinner Github

PopupActionSpinner.java

    package com.selva.widget;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListPopupWindow;
import android.widget.PopupWindow;
import android.widget.Spinner;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class PopupActionSpinner extends Spinner {

    private static final String M_POPUP = "mPopup";
    private static final String DROPDOWN_POPUP = "DropdownPopup";
    private static final String IS_SHOWING = "isShowing";
    private static final String DIALOG_POPUP = "DialogPopup";
    private static final int MODE_UNKNOWN = -1;

    private PopupTouchInterceptor popupTouchInterceptor;

    private Field mFieldSpinnerPopup = null;
    private PopupActionSpinner[] mPopupActionSpinnersArr = null;

    /**
     * Construct a new spinner with the given context theme and the supplied attribute set.
     *
     * @param context The Context the view is running in, through which it can
     *                access the current theme, resources, etc.
     * @param attrs   The attributes of the XML tag that is inflating the view.
     */
    public PopupActionSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Define your own Interface to control what happens when the Spinner dropdown popup is open.
     * @param mpopupTouchInterceptor
     */
    public void setPopupTouchInterceptor(PopupTouchInterceptor mpopupTouchInterceptor,
                                         PopupActionSpinner[] allSpinners  )
    {
        this.popupTouchInterceptor = mpopupTouchInterceptor;
        this.mPopupActionSpinnersArr = allSpinners;
    }


    @Override
    public boolean performClick() {
        boolean handled = true;

        try {
            handled = super.performClick();

            // reflecting Spinner.mPopup field
            if (isFieldSpinnerPopupNull()) {
                mFieldSpinnerPopup = this.getClass().getSuperclass().getDeclaredField(M_POPUP);
            }

            // disable access checks to Spinner.mPopup
            mFieldSpinnerPopup.setAccessible(true);

            // get value of mPopup field
            Object spinnerPopup = mFieldSpinnerPopup.get(this);

            // reflecting SpinnerPopup.isShowing()
            Method isShowing = mFieldSpinnerPopup.getType()
                    .getDeclaredMethod(IS_SHOWING, (Class[]) null);

            // calling Spinner.mPopup.isShowing()
            boolean isShowingResult = (boolean) isShowing.invoke(spinnerPopup, (Object[]) null);

            if (isShowingResult) {

                // check if mFieldSpinnerPopup is a dialog popup
                if (getSpinnerMode() == MODE_DIALOG) {
                    //Do Nothing
                } else if (getSpinnerMode() == MODE_DROPDOWN) {
                    // reflecting Spinner.mPopup.mPopup
                    Field fieldPopupWindow = ListPopupWindow.class.getDeclaredField(M_POPUP);
                    fieldPopupWindow.setAccessible(true);

                    ((PopupWindow) fieldPopupWindow.get(spinnerPopup)).setTouchInterceptor(new OnTouchListener() {
                        @Override
                        public boolean onTouch(View view, MotionEvent event) {


                            switch (event.getAction()) {
                                case MotionEvent.ACTION_DOWN: {
                                    if(!isViewInBounds(view,event.getRawX(),event.getRawY())) {
                                        for (View spinnerView : mPopupActionSpinnersArr)

                                            if (isPointInsideView(event.getRawX(), event.getRawY(), spinnerView)) {
                                                popupTouchInterceptor.onTouchIntercepted(spinnerView);
                                                break;
                                            }
                                    }
                                    break;
                                }

                            }

                            return false;
                        }
                    });
                    fieldPopupWindow.setAccessible(false);
                }
            }

            // enable access checks to Spinner.mPopup
            mFieldSpinnerPopup.setAccessible(false);

        } catch (Exception exception) {
        }
        return handled;
    }

    public static boolean isPointInsideView(float x, float y, View view){
        int location[] = new int[2];
        view.getLocationOnScreen(location);
        int viewX = location[0];
        int viewY = location[1];

        //point is inside view bounds
        if(( x > viewX && x < (viewX + view.getWidth())) &&
                ( y > viewY && y < (viewY + view.getHeight()))){
            return true;
        } else {
            return false;
        }
    }

    private boolean isViewInBounds(View view, float x, float y) {
        Rect outRect = new Rect();
        int[] location = new int[2];
        view.getDrawingRect(outRect);
        view.getLocationOnScreen(location);
        outRect.offset(location[0], location[1]);
        return outRect.contains((int)x, (int)y);
    }

    /**
     * Returns a constant describing how the user selects choices from the spinner.
     *
     * @return the choosing mode of this <code>{@link Spinner}</code>
     */
    public int getSpinnerMode() {
        int result = MODE_UNKNOWN;

        try {
            // reflecting Spinner.mPopup field
            if (isFieldSpinnerPopupNull()) {
                mFieldSpinnerPopup = this.getClass().getSuperclass().getDeclaredField(M_POPUP);
            }

            // get Spinner.DropdownPopup class name
            mFieldSpinnerPopup.setAccessible(true);
            String spinnerPopupClassName = mFieldSpinnerPopup.get(this).getClass().getSimpleName();
            mFieldSpinnerPopup.setAccessible(false);

            switch (spinnerPopupClassName) {
                case DIALOG_POPUP:
                    result = MODE_DIALOG;
                    break;
                case DROPDOWN_POPUP:
                    result = MODE_DROPDOWN;
                    break;
                default:
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        return result;
    }

    public boolean isFieldSpinnerPopupNull() {
        return mFieldSpinnerPopup == null;
    }

    @Override
    public int getId() {
        return super.getId();
    }
}

Я использовал Java Reflection для доступа к всплывающему окну и переопределения TouchInteceptor. Таким образом, вы сможете контролировать событие касания в своей деятельности, и в свою очередь вы сможете открыть следующий счетчик, не нажав дважды.

Чтобы получить четкое представление, клонируйте мой образец из Github и запустите его. Пожалуйста, дайте мне знать, если у вас есть какие-либо сомнения.

Ответ 3

Попробуйте использовать этот код, чтобы открыть свой счетчик, не нажимая на него.

 ((Spinner) findViewById(R.id.selected_area_spinner)).performClick();

Но используйте этот код после инициализации вашего spinner

Ответ 4

Попробуйте использовать этот код

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;



/**
 * Created by riyazudinp on 8/11/2016.
 */
public class MyActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener, View.OnClickListener {

    private String dataForSpinnerOne[] = {"A", "B", "C", "D", "E"};
    private String dataForSpinnerTwo[] = {"F", "G", "H", "I", "J"};
    private String dataForSpinnerThree[] = {"K", "L", "M", "N", "O"};
    private Spinner spinnerOne;
    private Spinner spinnerTwo;
    private Spinner spinnerThree;

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


        spinnerOne = (Spinner) findViewById(R.id.spinner1);
        spinnerTwo = (Spinner) findViewById(R.id.spinner2);
        spinnerThree = (Spinner) findViewById(R.id.spinner3);


        ArrayAdapter<String> adapter1 = new ArrayAdapter<>(MyActivity.this, android.R.layout.simple_list_item_1, dataForSpinnerOne);
        ArrayAdapter<String> adapter2 = new ArrayAdapter<>(MyActivity.this, android.R.layout.simple_list_item_1, dataForSpinnerTwo);
        ArrayAdapter<String> adapter3 = new ArrayAdapter<>(MyActivity.this, android.R.layout.simple_list_item_1, dataForSpinnerThree);

        spinnerOne.setAdapter(adapter1);
        spinnerTwo.setAdapter(adapter2);
        spinnerThree.setAdapter(adapter3);

        spinnerOne.setOnItemSelectedListener(this);
        spinnerTwo.setOnItemSelectedListener(this);
        spinnerThree.setOnItemSelectedListener(this);

        spinnerOne.setOnClickListener(this);
        spinnerTwo.setOnClickListener(this);
        spinnerThree.setOnClickListener(this);
    }

    @Override
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

        if (view == spinnerOne) {
            //Spinner One Clicked
            //add your code when spinner iten selected
        }
        if (view == spinnerTwo) {
            //Spinner Two Clicked
            //add your code when spinner iten selected
        }
        if (view == spinnerThree) {
            //Spinner Three Clicked
            //add your code when spinner iten selected
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> adapterView) {

    }

    @Override
    public void onClick(View view) {
        if (view == spinnerOne) {
            spinnerOne.performClick();
            spinnerTwo.performClick();
            spinnerThree.performClick();
        }
        if (view == spinnerTwo) {
            spinnerOne.performClick();
            spinnerTwo.performClick();
            spinnerThree.performClick();
        }
        if (view == spinnerThree) {
            spinnerOne.performClick();
            spinnerTwo.performClick();
            spinnerThree.performClick();
        }
    }
}

Ответ 5

anotherSpinner.setSelection(open_item_index);

Ответ 6

Это почти невозможно.

Иерархия класса Spinner

Spinner -> AbsSpinner -> AdapterView<SpinnerAdapter> -> ViewGroup -> View

Из Spinner.Java

/**
 * <p>A spinner does not support item click events. Calling this method
 * will raise an exception.</p>
 * <p>Instead use {@link AdapterView#setOnItemSelectedListener}.
 *
 * @param l this listener will be ignored
 */

У нас нет доступа к событию click.

OnClickListener uses public interface DialogInterface.

Лучшее, что я могу предложить, это использовать всплывающее меню вместо Spinner, если эта функция отключает вас.

@Zvi @Erfan Mowlaei, похоже, не публикует никакого кода. Вот моя идея его идеи:

        ViewTreeObserver vto1 = spinnerOne.getViewTreeObserver();
        vto1.addOnGlobalLayoutListener(new OnGlobalLayoutListener() 
        {
            @Override
            public void onGlobalLayout() 
            {
                if( !spinnerOne.getViewTreeObserver().isAlive() ) 
                {
                    Log.e(TAG,"OnGlobalLayoutListener: ***NOT alive***");
                    // only need to calculate once, so remove listener
//                  viewToMeasure.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }else
                {
                    Log.e(TAG,"OnGlobalLayoutListener: ***alive***");
                /*when you post a message to a View,
                the messages will only be delivered after
                the View has been fully initialized (including being measured)*/
                    spinnerOne .post(new Runnable() 
                    {
                        @Override
                        public void run() 
                        {
                            Log.e(TAG,"OnGlobalLayoutListener: ***run test***");
                            // safe to get height and width here  
                            spinnerTwo.setSelected(false);
                            spinnerThree.setSelected(false);
                            spinnerOne.performClick();
 //                         LayerDrawable ld = (LayerDrawable)spinnerOne.getBackground();//cast problem
 //                         ld.setLayerInset(1, 0, spinnerOne.getHeight() / 2, 0, 0);             
                        }
                    });
                }
            }
        });

Примечание: Как я сказал, ни один из этих методов не может работать, потому что события генерируются и потребляются в библиотеке времени выполнения. Они НИКОГДА не отображаются.

Другие вещи, которые работают не:

spinnerOne.setOnFocusChangeListener(new OnFocusChangeListener() 
{
    @Override
    public void onFocusChange(View v, boolean hasFocus)
    {
        if(hasFocus)
        {
            spinnerOne.performClick();

            Log.v(TAG, "onFocusChange spinnerOne GOT the focus");
            Toast.makeText(getApplicationContext(), "spinnerOne got the focus", Toast.LENGTH_SHORT).show();
        }else 
        {

            Log.v(TAG, "onFocusChange spinnerOne LOST the focus");
            Toast.makeText(getApplicationContext(), "spinnerOne lost the focus", Toast.LENGTH_SHORT).show();
        }
       }
    });

Новая надежда Эпизод IV?

Ваша проблема поднимает запись в logcat каждый раз, когда вы выполняете "маневр Zvi":

08-14 01:19:55.575: W/InputEventReceiver(8676): 
Attempted to finish an input event but
the input event receiver has already been disposed.

Я не очень надеюсь на это, решая проблему.