如何在另一个微调器打开时单击打开微调器

时间:2016-07-30 12:14:10

标签: android spinner

我在表单上的spinners很少。当我点击它们中的任何一个时,它会打开并显示选项。当我点击任何其他spinner时,它会关闭打开的spinner,但我需要再次点击所需的spinner才能打开它。

我想第一次点击第二个微调器,这样我就可以关闭第一个打开的微调器,然后打开单击的微调器。

我看过关于在外面的任何点击上关闭微调器的帖子,但这还不够,因为我仍然不知道所需的微调器被点击(第二个微调器的onclick()没有被触发)。 / p>

7 个答案:

答案 0 :(得分:1)

我有点忙于编写并提供一些代码,但是从this这样的链接获得帮助可以获得一些代码。所以这是我的想法。首先在创建视图时,获取微调器的坐标,例如微调器A,B和C.还要编写一个函数(例如foo(...)),它返回点击点的坐标但不是消耗它。然后注册A,B和C onItemSelectedListeners并在onNothingSelected检查点击点是否在旋转器的其他两个区域(使用您之前写的foo(...))。这样你就可以得到你想要的东西。对不起,我既忙又懒,但这很有效。我希望我帮助过你。

更新(接收触摸):

好吧,我尝试了几种方法,说实话其中没有一种方法有效,即使让活动拦截触摸事件没有帮助,所以我猜开启微调器的情况就像弹出窗口,在这种情况下,一个解决方案来到我的心。

您需要在所有视图的顶部放置一个透明图层来拦截触摸,但它应该像锁定屏幕中使用的那样,这样就不会有其他对话框或视图。如果您已经编写了锁屏应用程序或尝试过这样做,您就知道该怎么做了。

然而,对于这种情况,许可将是矫枉过正的,除非你找到另一种和平的方式,否则我不建议你去做。

答案 1 :(得分:1)

这是一个自定义微调器,可以完全满足您的需要,

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's 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克隆我的样本并运行相同的。如果您有任何疑问,请告诉我。

答案 2 :(得分:1)

无论您要为旋转器实现setOnItemClickListener的位置,都应编写此行代码:

spinner.requestFocusFromTouch();

这将告诉微调器一键调用并显示项目列表。

答案 3 :(得分:0)

尝试使用此一行代码打开您的微调器而不点击它

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

但是在初始化微调器之后使用此代码

答案 4 :(得分:0)

尝试使用此代码帮助您

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 :(得分:0)

anotherSpinner.setSelection(open_item_index);

答案 6 :(得分:0)

这几乎是不可能的。

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
 */

我们无法访问点击事件

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

新希望第四集?

每次执行“Zvi机动”时,您的问题确实会在logcat中引发一个条目:

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

我对解决这个问题并不抱太大希望。