J'essaie de charger un spinner sans valeur sélectionnée. Une fois que l'utilisateur sélectionne une valeur, il les dirige vers une autre page.
Cela s'avère être un problème car à l'heure actuelle, la page se charge tout de suite avant que l'utilisateur n'ait le choix.
Ma classe spinner est configurée de la même manière que celle de Google: http://developer.Android.com/resources/tutorials/views/hello-spinner.html
Donc, fondamentalement, est-il possible d'avoir un spinner qui charge avec rien sélectionné car à l'heure actuelle, il charge le premier élément de mon tableau de chaînes.
est-il possible d'avoir une roulette qui charge avec rien sélectionné
Seulement s'il n'y a pas de données. Si vous avez 1+ éléments dans la SpinnerAdapter
, la Spinner
aura toujours une sélection.
Spinners
ne sont pas conçus pour être des widgets de commande. Les utilisateurs ne s'attendent pas à une sélection dans une Spinner
pour démarrer une activité. Pensez à utiliser quelque chose d'autre, tel que ListView
ou GridView
, au lieu de Spinner
.
MODIFIER
Au fait, j'ai oublié de le mentionner - vous pouvez toujours insérer dans votre adaptateur une entrée supplémentaire qui représente "aucune sélection" et en faire l'élément sélectionné initialement dans la Spinner
.
Vous pouvez également remplacer votre adaptateur spinner et fournir une vue vide pour la position 0 dans votre méthode getView et une vue avec une hauteur de 0dp dans la méthode getDropDownView
.
De cette façon, vous avez un texte initial tel que "Sélectionnez une option ..." qui apparaît lorsque le compteur est chargé pour la première fois, mais ce n'est pas une option à choisir pour l'utilisateur , ils ne peuvent pas le voir).
Il s'agit d'une implémentation complète de idée de Paul Bourdeaux , à savoir le retour d'une vue initiale spéciale (ou une vue vide) dans getView()
pour la position 0.
Cela fonctionne pour moi et est relativement simple. Vous pouvez envisager cette approche en particulier si vous avez déjà un adaptateur personnalisé pour votre Spinner. (Dans mon cas, j’utilisais un adaptateur personnalisé pour personnaliser facilement la disposition des éléments, chaque élément ayant quelques TextViews.)
L'adaptateur serait quelque chose du genre:
public class MySpinnerAdapter extends ArrayAdapter<MyModel> {
public MySpinnerAdapter(Context context, List<MyModel> items) {
super(context, R.layout.my_spinner_row, items);
}
@Override
public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) {
if (position == 0) {
return initialSelection(true);
}
return getCustomView(position, convertView, parent);
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
if (position == 0) {
return initialSelection(false);
}
return getCustomView(position, convertView, parent);
}
@Override
public int getCount() {
return super.getCount() + 1; // Adjust for initial selection item
}
private View initialSelection(boolean dropdown) {
// Just an example using a simple TextView. Create whatever default view
// to suit your needs, inflating a separate layout if it's cleaner.
TextView view = new TextView(getContext());
view.setText(R.string.select_one);
int spacing = getContext().getResources().getDimensionPixelSize(R.dimen.spacing_smaller);
view.setPadding(0, spacing, 0, spacing);
if (dropdown) { // Hidden when the dropdown is opened
view.setHeight(0);
}
return view;
}
private View getCustomView(int position, View convertView, ViewGroup parent) {
// Distinguish "real" spinner items (that can be reused) from initial selection item
View row = convertView != null && !(convertView instanceof TextView)
? convertView :
LayoutInflater.from(getContext()).inflate(R.layout.my_spinner_row, parent, false);
position = position - 1; // Adjust for initial selection item
MyModel item = getItem(position);
// ... Resolve views & populate with data ...
return row;
}
}
C'est tout. Notez que si vous utilisez une OnItemSelectedListener
avec votre spinner, dans onItemSelected()
, vous devrez également ajuster position
pour prendre en compte l'élément par défaut, par exemple:
if (position == 0) {
return;
} else {
position = position - 1;
}
MyModel selected = items.get(position);
Dans mon cas, bien que la taille '2' soit affichée dans la roulette, rien ne se passe tant que la sélection n’est pas faite!
J'ai un fichier XML (data_sizes.xml) qui répertorie toutes les valeurs de spinner.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chunks">
<item>2</item>
<item>4</item>
<item>8</item>
<item>16</item>
<item>32</item>
</string-array>
</resources>
Dans le fichier main.xml: élément Spinner
<Spinner Android:id="@+id/spinnerSize"
Android:layout_marginLeft="50px"
Android:layout_width="fill_parent"
Android:drawSelectorOnTop="true"
Android:layout_marginTop="5dip"
Android:Prompt="@string/SelectSize"
Android:layout_marginRight="30px"
Android:layout_height="35px" />
Puis dans mon code Java, j'ai ajouté:
Dans mon activité: déclaration
Spinner spinnerSize;
ArrayAdapter adapter;
Dans une fonction vide publique - initControls (): Definition
spinnerSize = (Spinner)findViewById(R.id.spinnerSize);
adapter = ArrayAdapter.createFromResource(this, R.array.chunks, Android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(Android.R.layout.simple_spinner_dropdown_item);
spinnerSize.setAdapter(adapter);
spinnerSize.setOnItemSelectedListener(new MyOnItemSelectedListener());
Mon auditeur spinner:
/ * Spinner Listener * /
class MyOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
chunkSize = new Integer(parent.getItemAtPosition(pos).toString()).intValue();
}
public void onNothingSelected(AdapterView<?> parent) {
// Dummy
}
}
Utiliser une disposition spinner personnalisée comme ceci:
<?xml version="1.0" encoding="utf-8"?>
<Spinner xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/spinnerTarget"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:textSize="14dp"
Android:textColor="#000000"/>
Dans l'activité:
// populate the list
ArrayList<String> dataList = new ArrayList<String>();
for (int i = 0; i < 4; i++) {
dataList.add("Item");
}
// set custom layout spinner_layout.xml and adapter
Spinner spinnerObject = (Spinner) findViewById(R.id.spinnerObject);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, R.drawable.spinner_layout, dataList);
dataAdapter.setDropDownViewResource(Android.R.layout.simple_spinner_dropdown_item);
spinnerObject.setAdapter(dataAdapter);
spinnerObject.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// to set value of first selection, because setOnItemSelectedListener will not dispatch if the user selects first element
TextView spinnerTarget = (TextView)v.findViewById(R.id.spinnerTarget);
spinnerTarget.setText(spinnerObject.getSelectedItem().toString());
return false;
}
});
spinnerObject.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
private boolean selectionControl = true;
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// just the first time
if(selectionControl){
// find TextView in layout
TextView spinnerTarget = (TextView)parent.findViewById(R.id.spinnerTarget);
// set spinner text empty
spinnerTarget.setText("");
selectionControl = false;
}
else{
// select object
}
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
Fusionner ceci:
private long previousItemId = 0;
@Override
public long getItemId(int position) {
long nextItemId = random.nextInt(Integer.MAX_VALUE);
while(previousItemId == nextItemId) {
nextItemId = random.nextInt(Integer.MAX_VALUE);
}
previousItemId = nextItemId;
return nextItemId;
}
Avec ceci répondre :
public class SpinnerInteractionListener
implements AdapterView.OnItemSelectedListener, View.OnTouchListener {
private AdapterView.OnItemSelectedListener onItemSelectedListener;
public SpinnerInteractionListener(AdapterView.OnItemSelectedListener selectedListener) {
this.onItemSelectedListener = selectedListener;
}
boolean userSelect = false;
@Override
public boolean onTouch(View v, MotionEvent event) {
userSelect = true;
return false;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if(userSelect) {
onItemSelectedListener.onItemSelected(parent, view, pos, id);
userSelect = false;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
if(userSelect) {
onItemSelectedListener.onNothingSelected(parent);
userSelect = false;
}
}
}
vous pouvez mettre la première cellule de votre tableau vide ({"", "certains", "certains", ...}) et ne rien faire si la position est 0;
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position>0) {
label.setText(MainActivity.questions[position - 1]);
}
}
Ma solution, au cas où vous auriez un TextView comme chaque ligne du disque:
// TODO: add a fake item as the last one of "items"
final ArrayAdapter<String> adapter=new ArrayAdapter<String>(..,..,items)
{
@Override
public View getDropDownView(final int position,final View convertView,final ViewGroup parent)
{
final View dropDownView=super.getDropDownView(position,convertView,parent);
((TextView)dropDownView.findViewById(Android.R.id.text1)).setHeight(position==getCount()-1?0:getDimensionFromAttribute(..,R.attr.dropdownListPreferredItemHeight));
dropDownView.getLayoutParams().height=position==getCount()-1?0:LayoutParams.MATCH_PARENT;
return dropDownView;
}
}
...
spinner.setAdapter(adapter);
_actionModeSpinnerView.setSelection(dataAdapter.getCount()-1,false);
public static int getDimensionFromAttribute(final Context context,final int attr)
{
final TypedValue typedValue=new TypedValue();
if(context.getTheme().resolveAttribute(attr,typedValue,true))
return TypedValue.complexToDimensionPixelSize(typedValue.data,context.getResources().getDisplayMetrics());
return 0;
}
Je suppose que vous voulez avoir une Spinner
avec le premier élément invisible vide (c'est une caractéristique étrange de Spinner
qui ne peut pas afficher une liste sans sélectionner un élément). Vous devriez ajouter une classe qui contiendra des données:
data class YourData(val id: Int, val name: String?)
Ceci est l'adaptateur.
class YourAdapter(
context: Context,
private val textViewResourceId: Int,
private var items: ArrayList<YourData>
) : ArrayAdapter<YourData>(context, textViewResourceId, items) {
private var inflater: LayoutInflater = context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
override fun getCount(): Int = items.size + 1
override fun getItem(position: Int): YourData? =
if (position == 0) YourData(0, "") else items[position - 1]
override fun getItemId(position: Int): Long = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View =
if (position == 0) {
getFirstTextView(convertView)
} else {
getTextView(convertView, parent, position - 1)
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View =
getView(position, convertView, parent)
private fun getFirstTextView(convertView: View?): View {
// Just simple TextView as initial selection.
var textView: TextView? = convertView as? TextView
val holder: FirstViewHolder
if (textView?.tag !is FirstViewHolder) {
textView = TextView(context) // inflater.inflate(R.layout.your_text, parent, false) as TextView
textView.height = 0 // Hide first item.
holder = FirstViewHolder()
holder.textView = textView
textView.tag = holder
}
return textView
}
private fun getTextView(
convertView: View?,
parent: ViewGroup,
position: Int
): TextView {
var textView: TextView? = convertView as? TextView
val holder: ViewHolder
if (textView?.tag is ViewHolder) {
holder = textView.tag as ViewHolder
} else {
textView = inflater.inflate(textViewResourceId, parent, false) as TextView
holder = ViewHolder()
holder.textView = textView
textView.tag = holder
}
holder.textView.text = items[position].name
return textView
}
private class FirstViewHolder {
lateinit var textView: TextView
}
private class ViewHolder {
lateinit var textView: TextView
}
}
Créer:
YourAdapter(context!!, R.layout.text_item, ArrayList())
Pour ajouter des articles:
private fun fill(items: List<YourData>, adapter: YourAdapter) {
adapter.run {
clear()
addAll(items)
notifyDataSetChanged()
}
}
Lorsque vous chargez des éléments dans votre Spinner
avec cette commande fill()
, vous devez savoir que les index sont également incrémentés. Donc, si vous souhaitez sélectionner le 3ème élément, vous devez maintenant sélectionner le 4ème: spinner?.setSelection(index + 1)
Basé sur @Jonik answer, j'ai créé une extension entièrement fonctionnelle pour ArrayAdapter
class SpinnerArrayAdapter<T> : ArrayAdapter<T> {
private val selectText : String
private val resource: Int
private val fieldId : Int
private val inflater : LayoutInflater
constructor(context: Context?, resource: Int, objects: Array<T>, selectText : String? = null) : super(context, resource, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = 0
this.inflater = LayoutInflater.from(context)
}
constructor(context: Context?, resource : Int, objects: List<T>, selectText : String? = null) : super(context, resource, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = 0
this.inflater = LayoutInflater.from(context)
}
constructor(context: Context?, resource: Int, textViewResourceId: Int, objects: Array<T>, selectText : String? = null) : super(context, resource, textViewResourceId, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = textViewResourceId
this.inflater = LayoutInflater.from(context)
}
constructor(context: Context?, resource : Int, textViewResourceId: Int, objects: List<T>, selectText : String? = null) : super(context, resource, textViewResourceId, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = textViewResourceId
this.inflater = LayoutInflater.from(context)
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup?): View {
if(position == 0) {
return initialSelection(true)
}
return createViewFromResource(inflater, position -1, convertView, parent, resource)
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
if(position == 0) {
return initialSelection(false)
}
return createViewFromResource(inflater, position -1, convertView, parent, resource)
}
override fun getCount(): Int {
return super.getCount() + 1 // adjust for initial selection
}
private fun initialSelection(inDropDown: Boolean) : View {
// Just simple TextView as initial selection.
val view = TextView(context)
view.setText(selectText)
view.setPadding(8, 0, 8, 0)
if(inDropDown) {
// Hide when dropdown is open
view.height = 0
}
return view
}
private fun createViewFromResource(inflater: LayoutInflater, position: Int,
@Nullable convertView: View?, parent: ViewGroup?, resource: Int): View {
val view: View
val text: TextView?
if (convertView == null || (convertView is TextView)) {
view = inflater.inflate(resource, parent, false)
} else {
view = convertView
}
try {
if (fieldId === 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = view as TextView
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(fieldId)
if (text == null) {
throw RuntimeException("Failed to find view with ID "
+ context.getResources().getResourceName(fieldId)
+ " in item layout")
}
}
} catch (e: ClassCastException) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView")
throw IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e)
}
val item = getItem(position)
if (item is CharSequence) {
text.text = item
} else {
text.text = item!!.toString()
}
return view
}