djo
djo

Reputation: 253

Selected Spinner Item getting replaced by First row in the spinner

I have been working on a spinner which has a custom layout for the dropdown. Here's my problem, when I select, let's say the 2nd item in the drop down, it gets selected and the drop down closes. When I reopen the drop down, the first row remains the same but the second row gets renamed to the first row. But it tells when I print out a log.d into console, that position:2 was selected.

Here's my code,

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        TextView textView = (TextView) convertView.inflate(getContext(), android.R.layout.simple_spinner_item, null);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
        textView.setTextColor(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.blue));
        if(list.getIsRecent()){
            textView.setText("Most Recent ");
        } else {
            textView.setText(list.get(position).getName());
        }
        return textView;
    }

    public View getCustomView(final int position, View convertView, ViewGroup parent) {
        boolean isRecent;
        isRecent = list.get(position).getIsRecent();
        if (convertView == null) {
                convertView = inflater.inflate(R.layout.custom_spinner_layout, parent, false);
                savedSearchName = (TextView) convertView
                        .findViewById(R.id.custom_spinner_layout_text_view);


            btnDelete = (ImageButton) convertView
                        .findViewById(R.id.custom_spinner_layout_button);

            relativeLayoutContainer = (RelativeLayout) convertView.findViewById(R.id.relativeLayout_item_name_container);
            relativeLayoutContainer.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG,"relativeLayoutContainer: setOnClickListener: position"+position);
                    Method method = null;
                    if(mSavedSearchCriteriaSpinner != null) {
                        mSavedSearchCriteriaSpinner.setSelection(position);
                        try {
                            method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
                            method.setAccessible(true);
                            method.invoke(mSavedSearchCriteriaSpinner);
                        } catch (Exception  e) {
                            e.printStackTrace();
                        }
                    }
                }
            });


            if(isRecent){
                btnDelete.setVisibility(View.INVISIBLE);
                savedSearchName.setText(list.get(position).getName() + "MOSTRECENT");
            } else {
                savedSearchName.setText(list.get(position).getName());
                btnDelete.setVisibility(View.VISIBLE);

                btnDelete.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //AlertDialog
                });
            }

        }
        return convertView;
    }

Screenshots: Initial Spinner Initial Spinner

Spinner DropDown Spinner dropdown

Position 1 selected: Qwerty position 1 selected: qwerty

Reopening dropdown Reopening dropdown

And No, this is not a homework question.

Upvotes: 0

Views: 513

Answers (1)

Xavier Rubio Jansana
Xavier Rubio Jansana

Reputation: 6583

In getView(), you're using the convertView wrong. This can be either null or an old view that needs to be recycled. If it's null, you have to inflate a new view, as you're doing. If not, this is an old item that needs to be recycled (i.e. you need to modify the text, you don't even need to set text size and color again):

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView textView = convertView;
        if (convertView == null) {
            LayoutInflater li = LayoutInflater.from(parent);
            textView = (TextView) li.inflate(getContext(), android.R.layout.simple_spinner_item, null);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
            textView.setTextColor(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.blue));
        }
        if(list.getIsRecent()){
            textView.setText("Most Recent ");
        } else {
            textView.setText(list.get(position).getName());
        }
        return textView;
    }

Also, getCustomView is storing btnDelete and savedSearchName in fields in your object, and probably this is messing up with old contents. Also, update the convertView always (now, if convertView is not null you don't update it):

public View getCustomView(final int position, View convertView, ViewGroup parent) {
    boolean isRecent;
    isRecent = list.get(position).getIsRecent();
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.custom_spinner_layout, parent, false);
    }

    TextView savedSearchName = (TextView) convertView.findViewById(R.id.custom_spinner_layout_text_view);


    ImageButton btnDelete = (ImageButton) convertView.findViewById(R.id.custom_spinner_layout_button);

    RelativeLayout relativeLayoutContainer = (RelativeLayout) convertView.findViewById(R.id.relativeLayout_item_name_container);
    relativeLayoutContainer.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG,"relativeLayoutContainer: setOnClickListener: position"+position);
            Method method = null;
            if(mSavedSearchCriteriaSpinner != null) {
                mSavedSearchCriteriaSpinner.setSelection(position);
                try {
                    method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
                    method.setAccessible(true);
                    method.invoke(mSavedSearchCriteriaSpinner);
                } catch (Exception  e) {
                    e.printStackTrace();
                }
            }
        }
    });


    if(isRecent){
        btnDelete.setVisibility(View.INVISIBLE);
        savedSearchName.setText(list.get(position).getName() + "MOSTRECENT");
    } else {
        savedSearchName.setText(list.get(position).getName());
        btnDelete.setVisibility(View.VISIBLE);

        btnDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    //AlertDialog
            });
    }

    return convertView;
}

About storing savedSearchName and btnDelete in fields, I guess is because you want to avoid searching them again. In that case I'd suggest using a holder pattern. See for example Hold View Objects in a View Holder in the following Google guide.

Upvotes: 1

Related Questions