public static long randomLong(long min, long max)
{
try
{
Random random = new Random();
long result = min + (long) (random.nextDouble() * (max - min));
return result;
}
catch (Throwable t) {t.printStackTrace();}
return 0L;
}
Вот общее решение, которое отменяет представление Spinner
. Он переопределяет setAdapter ()
, чтобы установить начальную позицию на -1, и проксирует предоставленный SpinnerAdapter
для отображения строки приглашения для позиции меньше 0.
Это было протестировано на Android от 1.5 до 4.2, но покупатель будьте осторожны! Поскольку это решение использует отражение для вызова частных AdapterView.setNextSelectedPositionInt ()
и AdapterView.setSelectedPositionInt ()
, его работа в будущих обновлениях ОС не гарантируется. Кажется вероятным, что так и будет, но это отнюдь не гарантировано.
Обычно я бы не потворствовал подобному, но этот вопрос задавали достаточно много раз, и он кажется достаточно разумным, и я решил опубликовать свое решение.
/**
* A modified Spinner that doesn't automatically select the first entry in the list.
*
* Shows the prompt if nothing is selected.
*
* Limitations: does not display prompt if the entry list is empty.
*/
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);
}
}
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);
}
}
}
Лучшее решение, которое я нашел для этого, не состоит в том, чтобы на самом деле использовать Счетчик, но AutoCompleteTextView. В основном EditText с приложенным Счетчиком для показывания предложений, поскольку Вы вводите - но с правильной конфигурацией он может вести себя точно как пожелания OP и т.д.
XML:
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="@+id/input"
android:hint="Select one"
style="@style/AutoCompleteTextViewDropDown"/>
</com.google.android.material.textfield.TextInputLayout>
Стиль:
<style name="AutoCompleteTextViewDropDown">
<item name="android:clickable">false</item>
<item name="android:cursorVisible">false</item>
<item name="android:focusable">false</item>
<item name="android:focusableInTouchMode">false</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
Что касается адаптера используют основной ArrayAdapter или расширяют его для создания собственного, но никакая дополнительная настройка на стороне адаптера не необходима. Установите адаптер на AutoCompleteTextView.
shared_ptr
won' t уходят, прежде чем переменная стека делает. Но it' s НАМНОГО более эффективный, чем создание копии на "куче". И ybungalobill корректен, это - единственный технически корректный ответ на вопрос, как указано. Это не заслужило downvote.
– Omnifarious
11 December 2011 в 19:10
Во-первых, вас может заинтересовать атрибут подсказки
класса Spinner
. См. Рисунок ниже: «Выберите планету» - это приглашение, которое можно установить в XML с помощью android: prompt = ""
.
Я собирался предложить подкласс Spinner
, где вы можете поддерживать два адаптера внутри. Один адаптер с параметром «Выбрать один», а другой реальный адаптер (с фактическими параметрами), затем с помощью OnClickListener
переключить адаптеры до отображения диалогового окна выбора. Однако, попробовав реализовать эту идею, я пришел к выводу, что вы не можете получать события OnClick
для самого виджета.
Вы можете обернуть счетчик в другом представлении, перехватить щелчки в представлении, а затем указать своему CustomSpinner
переключить адаптер, но это выглядит ужасным взломом.
Вам действительно нужно отображать «Выбрать один»?
Я нашел это решение:
String[] items = new String[] {"Select One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
items[0] = "One";
selectedItem = items[position];
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
Просто измените array[0] на "Select One", а затем в onItemSelected переименуйте его в "One".
Не самое стильное решение, но оно работает :D