/** * Copyright (c) 2013, Redsolution LTD. All rights reserved. * * This file is part of Xabber project; you can redistribute it and/or * modify it under the terms of the GNU General Public License, Version 3. * * Xabber is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License, * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.xabber.android.ui.widget; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TextView; /** * A modified Spinner that doesn't automatically select the first entry in the * list. * <p/> * Shows the prompt if nothing is selected. * <p/> * Limitations: does not display prompt if the entry list is empty. * <p/> * http://stackoverflow.com/a/3427058 * * @author emmby */ public class NoDefaultSpinner extends Spinner { public NoDefaultSpinner(Context context) { super(context); } public NoDefaultSpinner(Context context, AttributeSet attrs) { super(context, attrs); } public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setAdapter(SpinnerAdapter orig) { final SpinnerAdapter adapter = newProxy(orig); super.setAdapter(adapter); try { final Method m = AdapterView.class.getDeclaredMethod( "setNextSelectedPositionInt", int.class); m.setAccessible(true); m.invoke(this, -1); final Method n = AdapterView.class.getDeclaredMethod( "setSelectedPositionInt", int.class); n.setAccessible(true); n.invoke(this, -1); } catch (Exception e) { throw new RuntimeException(e); } } protected SpinnerAdapter newProxy(SpinnerAdapter obj) { return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(obj .getClass().getClassLoader(), new Class[]{SpinnerAdapter.class}, new SpinnerAdapterProxy( obj)); } /** * Intercepts getView() to display the prompt if position < 0 */ protected class SpinnerAdapterProxy implements InvocationHandler { protected SpinnerAdapter obj; protected Method getView; protected SpinnerAdapterProxy(SpinnerAdapter obj) { this.obj = obj; try { this.getView = SpinnerAdapter.class.getMethod("getView", int.class, View.class, ViewGroup.class); } catch (Exception e) { throw new RuntimeException(e); } } @Override public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { try { return m.equals(getView) && (Integer) (args[0]) < 0 ? getView( (Integer) args[0], (View) args[1], (ViewGroup) args[2]) : m.invoke(obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException(e); } } protected View getView(int position, View convertView, ViewGroup parent) throws IllegalAccessException { if (position < 0) { final TextView v = (TextView) ((LayoutInflater) getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE)) .inflate(android.R.layout.simple_spinner_item, parent, false); v.setText(getPrompt()); return v; } return obj.getView(position, convertView, parent); } } }