Android-----RecyclerView嵌套Spinner onItemSelected问题

在使用RecyclerView嵌套Spinner时会出现这样一个问题:改变第一个spinner的值时,下面有些隐藏的spinner的选项也跟着改变,然后我又往上拉,刚刚选的又改变,重复操作,隐藏起来的每次都会变

分析了一下原因:如果一页显示10个item,第一个滚不见了,第十一个出现的时候,可能复用的第一个item,如果不重新设置监听,spinner选择改变的是第一个itemi的选择。并且每次onBindViewHolder的时候,标题和spinner的属性都需要重新设置

第一种解决方法:继承spinner,在spinner中做一些操作

package com.org.youtu;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.support.v7.widget.AppCompatSpinner;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Spinner;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by Administrator on 2020/9/10.
 */

public class MySpinnerView extends AppCompatSpinner {

    private ItemClick mItemClick;



    public MySpinnerView(Context context) {
        super(context);
        init();
    }

    public MySpinnerView(Context context, int mode) {
        super(context, mode);
        init();
    }

    public MySpinnerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MySpinnerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public MySpinnerView(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
        super(context, attrs, defStyleAttr, mode);
        init();
    }

    public MySpinnerView(Context context, AttributeSet attrs, int defStyleAttr, int mode, Resources.Theme popupTheme) {
        super(context, attrs, defStyleAttr, mode, popupTheme);
        init();
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void init() {
        Class<?> myClass = Spinner.class;
        try {
            Class<?>[] params = new Class[1];
            params[0] = OnItemClickListener.class;
            Method m = myClass.getDeclaredMethod("setOnItemClickListenerInt", params);
            m.setAccessible(true);
            m.invoke(this, new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Class<?> myClass = AdapterView.class;
                    try {
                        Field field = myClass.getDeclaredField("mOldSelectedPosition");
                        field.setAccessible(true);                                          //设置mOldSelectedPosition可访问
                        field.setInt(MySpinnerView.this, AdapterView.INVALID_POSITION);     //设置mOldSelectedPosition的值

                        mItemClick.onClick(position);

                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public void setItemClick(ItemClick itemClick){
        this.mItemClick = itemClick;
    }

    public interface ItemClick {
        void onClick(int position);
    }

}

在子项布局中使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:background="@color/colorPrimary"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textview"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:layout_marginLeft="25dp"
            android:text=""
            android:textSize="18sp"
            android:textColor="#ffffff"/>

        <com.org.youtu.MySpinnerView
            android:id="@+id/spinnerSel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:entries="@array/spinnerVal">

        </com.org.youtu.MySpinnerView>

    </LinearLayout>



</LinearLayout>

适配器中:

package com.org.youtu.Adapter;

import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;

import com.org.youtu.MySpinnerView;
import com.org.youtu.R;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2020/9/7.
 */

public class recyclerViewAdapter extends RecyclerView.Adapter<recyclerViewAdapter.viewHolder> implements View.OnClickListener{

    public static String [] Groups = {"车辆唯一性检查","车辆特征参数检查","车辆外观检查","安全装置检查"};
    public static String [] AJCheckContens = {
            "号牌号码/车辆类型","车辆品牌/型号","车辆识别代号(或整车出厂编号)","发动机号码(或电动机号码)","车辆颜色和形状",
            "核定载人数","核定载质量",
            "车身外观","外观标识、标注和标牌","外部照明和信号灯具","轮胎","号牌和号码安装","加装/改装灯具",
            "汽车安全带","机动车用三角警告牌","灭火器","行驶记录装置","车身反光标识",
    };

    public Map<String , String> map = null;

    public RecyclerView recyclerView;

    private RVItemClickListener rvClickListener = null;

    private viewHolder holder = null;

    public void setRecyclerViewClickListener(RVItemClickListener recyclerViewListener){
        this.rvClickListener = recyclerViewListener;
    }


    public recyclerViewAdapter(RecyclerView rv){
        map = new HashMap<>();
        for (int i = 0 ; i< AJCheckContens.length ; i ++){
            map.put(i+"","1");
            Log.e("map中的数据",map.get(i+"") + "		map的长度:		"+ map.size());
        }
        this.recyclerView = rv;
    }

    @Override
    public viewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tab_item_view,parent,false);
        view.setOnClickListener(this);
        holder = new viewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final viewHolder holder, final int position) {
        holder.listCarID.setText(AJCheckContens[position]);
        holder.spinner.setItemClick(new MySpinnerView.ItemClick() {
            @Override
            public void onClick(int position) {
                Log.e("spinner设置点击监听","监听点击成功");
            }
        });
        holder.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                LinearLayout layout = (LinearLayout) view.getParent().getParent();          //通过spinner组件选项拿到父组件Layout
                TextView textView = (TextView) layout.getChildAt(0);                     //通过父组件拿到子组件TextView
                TextView selectVal = (TextView) view;                                       //选中的值
                Log.e("选中的值",selectVal.getText()+"	选项:	" + textView.getText());


                holder.update(textView.getText().toString(),position);


                for (int n = 0 ; n < AJCheckContens.length ; n ++){
                    if (AJCheckContens[n].equals(textView.getText().toString().trim())){
                        if (selectVal.getText().equals("不合格")){
                            map.put(n+"","0");
                        }else {
                            map.put(n+"","1");
                        }
                        Log.e("字段所在位置",(n+1) + "	map的key值:	" + getMapKey(textView.getText().toString()) +"	改变后的值:	" + map.get(n+""));
                        break;
                    }
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
    }

    @Override
    public int getItemCount() {
        return AJCheckContens.length;
    }



    @Override
    public void onClick(View view) {

        if (rvClickListener != null){
            int position = recyclerView.getChildAdapterPosition(view);
            rvClickListener.onItemClick(recyclerView,view,position,AJCheckContens[position]);
        }

    }

    /**【定义一个内部类,展示的数据由内部类决定】**/
    static class viewHolder extends RecyclerView.ViewHolder{
        private TextView listCarID;
        private MySpinnerView spinner;
        public viewHolder(View view) {
            super(view);
            listCarID = view.findViewById(R.id.textview);
            spinner = view.findViewById(R.id.spinnerSel);
        }

        public void update(String title , int position){
            listCarID.setText(title);
            spinner.setSelection(position);
            spinner.setItemClick(new MySpinnerView.ItemClick() {
                @Override
                public void onClick(int position) {
                    Log.e("更新监听","监听更新成功");
                }
            });
        }
    }
}

然后在Activity中:

package com.org.youtu;

import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.gavin.com.library.StickyDecoration;
import com.gavin.com.library.listener.GroupListener;
import com.org.youtu.Adapter.RVItemClickListener;
import com.org.youtu.Adapter.recyclerViewAdapter;

import java.util.HashMap;
import java.util.Map;

public class recyclerViewActivity extends AppCompatActivity {

    RecyclerView recyclerViewUse;
    Button start , commit;
    recyclerViewAdapter adapter;

    public static String [] Groups = {"车辆唯一性检查","车辆特征参数检查","车辆外观检查","安全装置检查"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.recycler_view);

        recyclerViewUse = findViewById(R.id.recyclerViewUse);

        GroupListener groupListener = new GroupListener() {
            @Override
            public String getGroupName(int position) {
                return groupName(position);
            }
        };

        StickyDecoration decoration = StickyDecoration.Builder.init(groupListener)
                .setGroupHeight(40).setGroupTextSize(15).build();

        LinearLayoutManager manager = new LinearLayoutManager(this);
        recyclerViewUse.setLayoutManager(manager);
        recyclerViewUse.addItemDecoration(decoration);

        adapter = new recyclerViewAdapter(recyclerViewUse);
        adapter.setRecyclerViewClickListener(new RVItemClickListener() {
            @Override
            public void onItemClick(RecyclerView parent, View view, int position, String data) {
                //view.setBackgroundColor(Color.GREEN);
                TextView textView = (TextView) view.findViewById(R.id.textview);
                textView.setTextColor(Color.RED);
                Log.e("点击的位置","		" + position + "	数据:	" + data);
            }
        });
        recyclerViewUse.setAdapter(adapter);

        start = findViewById(R.id.Start);
        commit = findViewById(R.id.Commit);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LogMapInfo(adapter.map);
            }
        });

        commit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });

    }

    public String groupName(int position){
        if (position == 0){
            return "车辆唯一性检查";
        }else if (position == 5){
            return "车辆特征参数检查";
        }else if (position == 7){
            return "车辆外观检查";
        }else if (position == 13){
            return "安全装置检查";
        }else {
            return null;
        }

    }

    //打印map中的内容
    public void LogMapInfo(Map<String , String> map){
        for (int i = 1;i<map.size();i++){
            try {
                Thread.sleep(1000);
                Log.e("打印内容",map.get(""+i) +"		" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}

运行效果图:某些手机上可以,但是在我的手机上却是没有作用,所以我换了一种方法来实现

第二种方法:使用textView来替代spinner、因为我这里是只有两个选项,所以我直接用最简单的方式来实现、若要实现下拉效果,可以使用popupWindow,或者使用弹出框来替代

text view实现方式:子项布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:gravity="center"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textTitle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        />

    <TextView
        android:id="@+id/textResult"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        />

</LinearLayout>

主体布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.org.youtu.recyclerViewActivity">



    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">



            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerViewUse"
                android:layout_width="match_parent"
                android:layout_marginBottom="50dp"
                android:layout_height="wrap_content">

            </android.support.v7.widget.RecyclerView>




        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_alignParentBottom="true">

            <Button
                android:id="@+id/Start"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:text="检验开始" />

            <Button
                android:id="@+id/Commit"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:text="提交数据"/>

        </LinearLayout>
    </RelativeLayout>

</LinearLayout>

适配器:adapter

package com.org.youtu.Adapter;

import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.org.youtu.R;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2020/9/10.
 */

public class MyTextAdapter extends RecyclerView.Adapter<MyTextAdapter.viewHolder>{


    private MyTextAdapter.viewHolder holder = null;
    private List<checkResult> resultList;
    public Map<String , String> map;

    public MyTextAdapter(List<checkResult> list){
       this.resultList = list;
       map = new HashMap<>();
       for (int i = 0 ; i < list.size(); i ++){
           map.put(""+i,"1");
       }

    }


    @Override
    public viewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_item,parent,false);
        holder = new viewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final viewHolder holder,final int position) {
        if (resultList.get(position).isCheck()){
            holder.result.setText("合格");
            holder.result.setTextColor(Color.GREEN);
        }else {
            holder.result.setText("不合格");
            holder.result.setTextColor(Color.RED);
        }
        holder.title.setText(resultList.get(position).getTitle());
        holder.result.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("position的值为","		"+position);
                if (resultList.get(position).isCheck()){
                    holder.result.setText("不合格");
                    holder.result.setTextColor(Color.RED);
                    resultList.get(position).setCheck(false);
                    map.put(""+position,"0");
                }else {
                    holder.result.setText("合格");
                    holder.result.setTextColor(Color.GREEN);
                    resultList.get(position).setCheck(true);
                    map.put(""+position,"1");
                }
            }
        });
    }


    @Override
    public int getItemCount() {
        return resultList.size();
    }


    static class viewHolder extends RecyclerView.ViewHolder {
        private TextView title , result;

        public viewHolder(View view) {
            super(view);
            title = view.findViewById(R.id.textTitle);
            result = view.findViewById(R.id.textResult);
        }
    }

}

实体类:checkResult

package com.org.youtu.Adapter;

/**
 * Created by Administrator on 2020/9/10.
 */

public class checkResult {

    private String title;
    private String result;
    private boolean isCheck;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public boolean isCheck() {
        return isCheck;
    }

    public void setCheck(boolean check) {
        isCheck = check;
    }
}

Activity中处理代码:

package com.org.youtu;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.gavin.com.library.StickyDecoration;
import com.gavin.com.library.listener.GroupListener;
import com.org.youtu.Adapter.MyTextAdapter;
import com.org.youtu.Adapter.checkResult;

import java.util.ArrayList;
import java.util.List;

public class recyclerViewTextView extends AppCompatActivity {

    public static String [] AJCheckContens = {
            "号牌号码/车辆类型","车辆品牌/型号","车辆识别代号(或整车出厂编号)","发动机号码(或电动机号码)","车辆颜色和形状",
            "核定载人数","核定载质量",
            "车身外观","外观标识、标注和标牌","外部照明和信号灯具","轮胎","号牌和号码安装","加装/改装灯具",
            "汽车安全带","机动车用三角警告牌","灭火器","行驶记录装置","车身反光标识",
    };


    private RecyclerView textRecyclerView;
    private Button textStart , textCommit;
    private List<checkResult> list;
    private MyTextAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view_text_view);

        init();
    }

    private void init(){

        list = new ArrayList<>();

        for (int i = 0 ; i< AJCheckContens.length ; i ++){
            checkResult result = new checkResult();
            result.setTitle(AJCheckContens[i]);
            result.setResult("合格");
            result.setCheck(true);
            list.add(result);
        }

        textRecyclerView = findViewById(R.id.textRecyclerView);

        GroupListener groupListener = new GroupListener() {
            @Override
            public String getGroupName(int position) {
                return groupName(position);
            }
        };
        StickyDecoration decoration = StickyDecoration.Builder.init(groupListener)
                .setGroupHeight(40).setGroupTextSize(15).build();

        LinearLayoutManager manager = new LinearLayoutManager(this);

        textRecyclerView.setLayoutManager(manager);

        textRecyclerView.addItemDecoration(decoration);


        adapter = new MyTextAdapter(list);
        textRecyclerView.setAdapter(adapter);

        textStart = findViewById(R.id.textStart);
        textStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });
        textCommit = findViewById(R.id.textCommit);
        textCommit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                for (int n = 0; n < adapter.map.size() ; n ++){
                    Log.e("map中的值",adapter.map.get(n+"") + "	n的值:	" + n);
                }
            }
        });
    }

    public String groupName(int position){
        String name = null;
        if (position == 0){
            name = "车辆唯一性检查";
            return name;
        }else if (position == 5){
            name = "车辆特征参数检查";
            return name;
        }else if (position == 7){
            name = "车辆外观检查";
            return name;
        }else if (position == 13){
            name = "安全装置检查";
            return name;
        }else{
            return null;
        }

    }
}

运行结果:隐藏再拉出之后,不会改变已选择的数据,只有点击的时候才会改变展示的结果

最后提交map中的数据结果:正是我们选择的结果,至此大功告成。

原文地址:https://www.cnblogs.com/xiobai/p/13647084.html