滚动到屏幕之外后如何从recyclerview中的视图获取值 [英] How to get values from views in a recyclerview after they are scrolled out of screen

查看:70
本文介绍了滚动到屏幕之外后如何从recyclerview中的视图获取值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含RecyclerView的片段.该RecyclerView将包含几种不同类型的视图(EditText,Seekbar,CheckBox等),并且它将作为一种Form工作.我还有一个按钮执行保存,该按钮应该转到RecyclerView的每一行并获取用户输入的值.

I have a fragment that contains a RecyclerView. This RecyclerView will contain several different types of views (EditText, Seekbar, CheckBox, etc..) and it will work as a sort of Form. I have also a button the performs a save, that should go to each row of the RecyclerView and get the value the user inputs.

我还有一个适配器,可以根据要在RecyclerView上添加的视图类型来增加不同的布局.在此适配器中,我有一个"getValuesFromViews"方法,该方法根据视图类型读取用户输入.

I also have an Adapter that inflates different layouts depending on the type of view I want to add on the RecyclerView. In this adapter, i have a "getValuesFromViews" method that reads the user input depending on the view type.

public String getValuesFromViews(int position,ViewHolder vHolder){
 //...
}

在我的片段中,在For循环中,在使用findViewHolderForAdapterPosition获得ViewHolder之后,我调用此方法

In my fragment, during a For loop, I call this method, after getting a ViewHolder with findViewHolderForAdapterPosition

我的问题是,当我滚动RecyclerView时,我丢失了ViewHolders而不是屏幕上未显示的位置,因此findViewHolderForAdapterPosition返回null.

My problem is that when I scroll my RecyclerView, I lose the ViewHolders for the positions not shown on screen and so the findViewHolderForAdapterPosition returns null.

如何从屏幕上未显示的视图中读取值?

How can I read values from views not shown on screen?

编辑这是我的适配器(目前仍在使用).

EDIT here is my adapter at the moment (still working on it).

public class ParamsAdapter extends RecyclerView.Adapter<ParamsAdapter.ViewHolder> {
    private final android.support.v4.app.FragmentManager fragmentManager;
    private final Fragment fragment;
    private Context context;
    private View view1;


    ParamsAdapter.ViewHolder viewHolder1;
    List<UserConfigurableParametersResponseMainItem1> listParams;

    public ParamsAdapter(Context context1, List<UserConfigurableParametersResponseMainItem1> list, android.support.v4.app.FragmentManager fmanager, Fragment frag){
        context = context1;
        listParams = list;
        fragmentManager = fmanager;
        fragment = frag;
    }

    public List<UserConfigurableParametersResponseMainItem1> getListParams() {
        return listParams;
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        @BindView(R.id.tv_param_title)
        TextViewMPOS tvParamTitle;
        @BindView(R.id.iv_question)
        ImageView ivQuestion;
        @Nullable @BindView(R.id.et_param)
        View param;
        @BindView(R.id.param_loader)
        AVLoadingIndicatorView loader;
        @BindView(R.id.iv_status)
        ImageView iv_status;
        @BindView(R.id.iv_error)
        ImageView iv_error;
        @BindView(R.id.tv_param_error)
        TextViewMPOS tvError;
        @BindView(R.id.iv_reset)
        ImageView ivReset;

        public ViewHolder(View v){
            super(v);
            ButterKnife.bind(this,v);

        }
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    @Override
    public ParamsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){

        view1 = createViews(parent,viewType);
        viewHolder1 = new ParamsAdapter.ViewHolder(view1);

        return viewHolder1;
    }

    private View createViews(ViewGroup parent, int viewType) {
        ConfigurableParameterWebControlCode op = listParams.get(viewType).getParamWbCntrlCd();
        switch (op){
            case NUMERO:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_num,parent,false);
            case DOUBLE:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_double,parent,false);
            case EMAIL:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_email,parent,false);
            case TEXTBOX:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_text,parent,false);
            case TEXAREA:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_textarea,parent,false);
            case SLIDER:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_slider,parent,false);
            case CHECKBOX:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_num,parent,false);
            case DROPDOWN:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_drop,parent,false);
            case RADIOBUTTON:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_num,parent,false);
            case DATA:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_data,parent,false);
            case DATAHORA:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_datahora,parent,false);
            case TEMPO:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_tempo,parent,false);
/*            case PHONE:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_phone,parent,false);*/
            case CHECKGROUP:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_checkgroup,parent,false);
        }

        return null;
    }

    @Override
    public void onBindViewHolder(final ParamsAdapter.ViewHolder holder, final int position){

        final int index = getLanguageIndex(position);
        holder.tvParamTitle.setText(listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getLablTxt());
        holder.ivQuestion.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(context != null)
                    MyDialogBuilder.createSingleButtonDialog(context,R.drawable.ic_warningcor,listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getHlprTxt(),R.string.ok,null,-1).show();
            }
        });
        holder.ivReset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                clearView(holder,position);
            }
        });

        holder.iv_error.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(context != null)
                    MyDialogBuilder.createSingleButtonDialog(context,R.drawable.ic_errorcor,listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getErrTxt(),R.string.ok,null,-1).show();
            }
        });


        switch (listParams.get(position).getParamWbCntrlCd()){

            case NUMERO:
            case DOUBLE:
            case EMAIL:
            case TEXTBOX:
            case TEXAREA:
            case TELEFONE:
                EditTextMPOS editTextAux = (EditTextMPOS)holder.param;
                if (editTextAux != null) {
                    editTextAux.setText(listParams.get(position).getParamVl());
                }
                break;
            case SLIDER:
                AppCompatSeekBar seekbarAux = (AppCompatSeekBar)holder.param;
                seekbarAux.setMax(Integer.parseInt(listParams.get(position).getParamVldtnMax()));
                seekbarAux.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                        holder.tvParamTitle.setText(listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getLablTxt() +"   "+i);
                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }
                });
                break;
            case CHECKBOX:
                break;
            case DROPDOWN:
                break;
            case RADIOBUTTON:
                break;

            case DATA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDateNoHoursPicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"# ",0);
                        }
                    });
                }
                break;
            case DATAHORA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDatePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"##",0);
                        }
                    });
                }
                break;
            case TEMPO:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogTimePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"###",0);
                        }
                    });
                }
                break;
            case CHECKGROUP:
                LinearLayout linearLayout = (LinearLayout)holder.param;
                List<String> checkList = new ArrayList<String>(Arrays.asList(listParams.get(position).getParamVldtnRgExp().split(";")));
                for(int i=0;i<checkList.size();i++){
                    CheckBox checkBox = new CheckBox(context);
                    checkBox.setText(checkList.get(i));
                    LinearLayout.LayoutParams newParams = new LinearLayout.LayoutParams(
                            RelativeLayout.LayoutParams.WRAP_CONTENT,
                            RelativeLayout.LayoutParams.WRAP_CONTENT);
                        newParams.weight = 1;
                        checkBox.setLayoutParams(newParams);

                    linearLayout.addView(checkBox,i);
                }
                break;
        }
    }

    private void clearView(ViewHolder holder, int position) {
        switch (listParams.get(position).getParamWbCntrlCd()){
            case NUMERO:
            case DOUBLE:
            case EMAIL:
            case TEXTBOX:
            case TEXAREA:
            case TELEFONE:
                EditTextMPOS auxView = (EditTextMPOS)holder.param;
                if (auxView != null) {
                    auxView.setText("");
                    auxView.setHint(listParams.get(position).getDfltVl());
                }
                listParams.get(position).setUseDefault(true);
                break;
            case CHECKBOX:
                break;
            case DROPDOWN:
                break;
            case RADIOBUTTON:
                break;
            case DATA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDateNoHoursPicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"# ",0);
                        }
                    });
                }
                break;
            case DATAHORA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDatePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"##",0);
                        }
                    });
                }
                break;
            case TEMPO:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogTimePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"###",0);
                        }
                    });
                }
                break;
            case CHECKGROUP:
                break;
        }
    }

    private int getLanguageIndex(int position) {
        int index = 0;
        String lang = HelperSharedPreferences.getSharedPreferencesString(context,HelperSharedPreferences.LANG,"pt-PT");
        for (int i=0; i<listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().size();i++) {
            if(listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(i).getLangCd().equals(lang)) {
                index = i;
                break;
            }
        }
        return index;
    }

    public String getValuesFromViews(int position,ViewHolder vHolder){
        String result = new String();
        if(listParams.get(position).isUseDefault()) {
            result = null;
        }
        else {
            switch (listParams.get(position).getParamWbCntrlCd()) {
                case NUMERO:
                case DOUBLE:
                case EMAIL:
                case TEXTBOX:
                case TEXAREA:
                case TELEFONE:
                    EditTextMPOS auxView = (EditTextMPOS) vHolder.param;
                    if (auxView != null) {
                        result = auxView.getText().toString();
                    }
                    break;
                case CHECKBOX:

                    break;
                case CHECKGROUP:
                    LinearLayout linearLayout = (LinearLayout)vHolder.param;
                    for(int i = 0;i<linearLayout.getChildCount();i++){
                        if(((CheckBox)linearLayout.getChildAt(i)).isChecked()){
                            result += ((CheckBox)linearLayout.getChildAt(i)).getText() + ";";
                        }
                    }
                    break;

            }
        }
        Logging.log("RESULT ",result);
        return result;
    }


    public void setStatus(final int position, ViewHolder vHolder,int status){
        if (status == 1) {
            vHolder.iv_status.setVisibility(View.VISIBLE);
            vHolder.iv_error.setVisibility(View.INVISIBLE);
            vHolder.param.setBackgroundResource(R.drawable.edit_text_background);
        } else if (status == 2) {
            vHolder.iv_status.setVisibility(View.INVISIBLE);
            vHolder.iv_error.setVisibility(View.VISIBLE);
            vHolder.param.setBackgroundResource(R.drawable.edit_text_error_background);
        } else {
            vHolder.iv_status.setVisibility(View.INVISIBLE);
            vHolder.iv_error.setVisibility(View.INVISIBLE);
            if (vHolder.param != null) {
                vHolder.param.setBackgroundResource(R.drawable.edit_text_background);
            }
        }
    }


    @Override
    public int getItemCount(){
        if(listParams != null)
            return listParams.size();
        else
            return 0;
    }

    public void update (List<UserConfigurableParametersResponseMainItem1> list){
        this.listParams.clear();
        this.listParams = list;
        setDataChanged();
    }

    public void setDataChanged(){
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                notifyDataSetChanged();
            }
        });
    }
}

和要创建它的数据即时通讯就是这样的事情

and the Data im getting to create it is an array of things like this

    {

    "ParamCd":"xxxxxxx",
    "ParamVl":"xxxxxxx",
    "DfltVl":" ",
    "ParamVldtnRgExp":".*",
    "ParamWbCntrlCd":"EMAIL",   
    "ParamOrdr":54,
    "UsrCnfgrblPrmtrsRspnItms":[
        {
            "LangCd":"pt-PT",
            "LablTxt":"xxxxxxx",
            "HlprTxt":"xxxxxxxxxxxxxx",
            "ErrTxt":"xxxxxxxxxxxxxxxxxxxxx"
        },
        {
            "LangCd":"en-UK",
            "LablTxt":"xxxxxxx",
            "HlprTxt":"xxxxxxxxxxxxxx",
            "ErrTxt":"xxxxxxxxxxxxxxxxxxxxx"
        }
    ]
}

"ParamWbCntrlCd"字段定义了出现在RecyclerView行中的视图类型

The field "ParamWbCntrlCd" is what defines the sort of view that appears in the RecyclerView Row

推荐答案

在Android中,适配器用于创建表示特定数据集的视图.您可以将适配器看作是 data display 之间的一种桥梁.

In Android, adapters are used to create views representing a specific dataset. You can see adapters as a kind of bridge between data and display.

因此,ViewHolder是在给定位置的数据表示.由于视图通常比纯数据占用更多的内存,因此 RecyclerView 在滚动时会重用它们.这就是为什么您无法检索与滚动到屏幕之外的视图相关联的数据的原因:那些ViewHolder已被回收,其视图的先前状态已丢失.

Therefore, ViewHolder are representations of your data at a given position. As views generally takes more memory than pure data, RecyclerView reuses them while scrolling. That's why you can't retrieve data associated with views that scrolled out of the screen: those ViewHolder have been recycled, and the previous state of their views has been lost.

为解决此问题,我建议您执行以下步骤:

To solve this problem, I suggests you the following steps:

  1. 创建 SparseArray< UserConfigurableParametersResponseMainItem1> 作为适配器的字段.此 SparseArray 将包含已被修改的模型对象的副本用户.
  2. 为您的ViewHolders中可以修改其内容的每个View配置侦听器.
  1. Create a SparseArray<UserConfigurableParametersResponseMainItem1> as a field of your Adapter. This SparseArray will contain copies of your model object that have been modified by the user.
  2. Configure listeners for each View in your ViewHolders whose content could be modified.

对于每个有趣的更改,调用 holder.getAdapterPosition()以检索此ViewHolder在数据集中的当前位置.使用该 position 来检查 SparseArray 中此位置是否存在对象.如果不存在,请从 listParams 的相同位置创建原始数据的副本.然后设置该对象的属性以反映用户所做的更改.

For each interesting change, call holder.getAdapterPosition() to retrieve the current position of this ViewHolder in the dataset. Use that position to check if an object exists at this position in the SparseArray. If it does not exist, create a copy of the original data at the same position from listParams. Then set the properties of this object to reflect the changes the user made.

该想法是维护用户在适配器中所做的修改的缓存".这样,用户所做的修改将不再丢失.

The idea is to maintain a "cache" of modifications made by user in the adapter. This way, modifications made by user are no longer lost.

  1. onBindViewHolder 中,从SparseArray中给定的 position 中检索数据.如果为 null ,则不会发出任何修改,您可以绑定来自 listParams 的数据.否则,用户已经进行了修改,您必须将其绑定而不是原始绑定.

  1. In onBindViewHolder, retrieve the data from the given position in the SparseArray. If it is null, then no modifications have been issued, and you can bind data from listParams. Otherwise, modifications have been made by user, and you have to bind those instead of your original.

创建方法 UserConfigurableParametersResponseMainItem1 getModificationsForPosition(int位置).此方法直接映射到 SparseArray 中包含的数据.这样,如果返回的值不是 null ,则调用 Fragment 会直接知道会发生修改.

Create a method UserConfigurableParametersResponseMainItem1 getModificationsForPosition(int position). This method directly maps to data contained in the SparseArray. This way, the calling Fragment is directly aware that a modification occur if the returned value is not null.

单击保存"按钮时,使用for循环为适配器的每个有效位置调用 getModificationsForPosition(i),检索所有已修改的对象,然后将它们保存在任何地方您想要的(SQLite或远程服务器).

When clicking on the "Save" button, use a for-loop to call getModificationsForPosition(i) for every valid position of your adapter, retrieving all modified objects, then save them wherever you want (SQLite or remote server).

根据保存的更改刷新适配器的数据集.例如,您可以用稀疏数组中的数据替换 listParams 中的数据.单击保存"按钮后,不要忘记清除稀疏数组.

Refresh your adapter's dataset based on saved changes. For example, you may replace data in listParams with the ones from the sparse array. Don't forget to clear the sparse array when the "Save" button has been clicked.

此构造具有以下优点:

  • 即使ViewHolders回收后,对视图的修改仍会保留.
  • 可以针对每个位置分别放弃修改.
  • 您只保存已修改的数据,这样更有效.

希望有帮助!

这篇关于滚动到屏幕之外后如何从recyclerview中的视图获取值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆