Search code examples
androiddialogspinnercustom-adaptercustomdialog

Spinner not working in custom Dialog - why?


I am trying to use a android Spinner in a Custom dialog, but when I tap on the Spinner the list with items opens and you can tap on them and the view closes, but none of the items gets selected. When I use the exact same code in a normal Fragment it works fine.

And since I found nothing helpful anywhere, is there something I need to know when using the spinner in a Dialog ?

CustomDialog Class:

public SelectionDialog(Activity context, ArrayAdapter<T> arrayAdapter, List<T> objects) {
    super(context);
    this.activity = context;
    this.arrayAdapter = arrayAdapter;
    this.objects = objects;
}



@SuppressLint("ResourceAsColor")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));

    View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_selection,null);

    setContentView(view);

    BodyMenuCard parentCard = view.findViewById(R.id.parentCard);
    parentCard.setHeader(header);

    TextView textView = parentCard.getCardBody().findViewById(R.id.bodyText);
    textView.setText(description);

    yesBtn = parentCard.getCardBody().findViewById(R.id.btn_yes);

    //spinner = parentCard.getCardBody().findViewById(R.id.employeeSpinner);
    spinner = view.findViewById(R.id.employeeSpinner);
    spinnerHandler = new EmployeeSpinnerHandler(getContext(), spinner, (List<Employee>) 
    toggleYesBtn(false);


    if (iconRessoruce != -1) parentCard.setIcon(iconRessoruce);
    if (backgroundColor != -1) parentCard.setCircleColor(backgroundColor);

    if (successfullCallback != null) yesBtn.setOnClickListener((v -> successfullCallback.onClick(this)));
    if (abbortCalllback != null) {
        parentCard.getCardBody().findViewById(R.id.btn_no).setOnClickListener((v -> abbortCalllback.onClick(this)));
    } else {
        parentCard.getCardBody().findViewById(R.id.btn_no).setOnClickListener(v -> this.dismiss());
    }
}

EmployeeSpinnerAdapter

public class EmployeeSpinnerAdapter extends ArrayAdapter<Employee> {

private Map<String, ColorStateList> employeeColors;

private List<Employee> employees;

private RandomMaterialColor randomColor;

public EmployeeSpinnerAdapter(Context context, List<Employee> employees) {
    super(context, R.layout.employee_spinner, employees);
    setDropDownViewResource(R.layout.employee_spinner);
    this.employees = employees;
    this.employeeColors = new HashMap<>();
}

private class ViewHolder {

    private GradientDrawable background;
    private TextView header;
    private TablePart idField;

    private ViewHolder(View view) {
        if (randomColor == null) randomColor = new RandomMaterialColor(view.getResources(), view.getContext());
        ImageView iv = view.findViewById(R.id.icon_view);
        background = (GradientDrawable) iv.getBackground().mutate();
        header = view.findViewById(R.id.header);
        idField = view.findViewById(R.id.description);
    }

    private void populate(Employee employee) {
        header.setText(employee.getName());
        idField.update(employee.getId());
        ColorStateList color = employeeColors.getOrDefault(employee.getId(), ColorStateList.valueOf(randomColor.getMatColor("A700")));
        background.setColor(color);
    }

}

@Override
public int getCount() {
    return employees.size();
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    return obtainView(position, convertView, parent);
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) 
{
    return obtainView(position, convertView, parent);
}

private View obtainView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        convertView = mInflater.inflate(R.layout.employee_spinner, parent, false);
        convertView.setTag(new ViewHolder(convertView));
    }
    ViewHolder vh = (ViewHolder) convertView.getTag();
    vh.populate(employees.get(position));
    return convertView;
}
}

EmployeeSpinnerHandler The purpose of the class is to have exacly the same code handling the Spinner inside a dialog and outside, to find the mistake.

public class EmployeeSpinnerHandler {

private Context context;

private Spinner spinner;

private EmployeeSpinnerAdapter adapter;

private List<Employee> employees;

public EmployeeSpinnerHandler(Context context, Spinner spinner, List<Employee> employees) {
    this.context = context;
    this.spinner = spinner;
    this.employees = employees;

    setUp();
}

private void setUp() {

    adapter = new EmployeeSpinnerAdapter(getContext(), employees);
    spinner.setAdapter(adapter);

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            FancyToast.makeText(getContext(), "selected: " + employees.get(position).getName(), Toast.LENGTH_LONG, FancyToast.SUCCESS, true).show();
            //toggleYesBtn(true);
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            //toggleYesBtn(false);
            FancyToast.makeText(getContext(), "selected: none", Toast.LENGTH_LONG, FancyToast.SUCCESS, true).show();
        }
    });

}

public void updateObjects(List<Employee> employees) {
    this.employees.clear();
    this.employees.addAll(employees);
    adapter.notifyDataSetChanged();
}
}

The Spinner inside the normal Fragment

spinner = view.findViewById(R.id.employeeSpinner);
    EmployeeSpinnerHandler spinnerHandler = new EmployeeSpinnerHandler(getContext(), spinner, objects);

Notice: In boath cases the date gets fetched from a REST-Api, but it still only works in the normal Fragment.

And now the problem is, if I use the EmployeeSpinnerHandler on a Spinner located in a normal Fragment it works, but if I am using the Spinner in the selection dialog, you can click the spinner and the items show up, but they arent selectable (see in the images).

Images:

Custom Dialog with Spinner

Popup from Spinner in custom Dialog, were you can see the data is present, but if clicked it only closes the popup view

Spinner Working inside the Normal Fragment


Solution

  • Adapter allow single focus view make android:focusable="false" for all other itemsandroid:focusable="true" for your TextView which holds the title it will work.