在使用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中的数据结果:正是我们选择的结果,至此大功告成。