为什么 EditText 中的输入值在 RecyclerView 中滚动时会交换位置? [英] Why does the input value in EditText swaps its position while scrolling in a RecyclerView?

查看:18
本文介绍了为什么 EditText 中的输入值在 RecyclerView 中滚动时会交换位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 EditText 中输入输入后,如果快速向上或向下滚动,则输入值会在 RecyclerView 的另一个 EditText 中交换其位置.
滚动数据之前是在第一个 EditText 中.
上下滚动后,第一个 EditText 的值将其位置更改为第四个,并且交换是随机的.有什么办法可以稳定数据.

After putting an input in the EditText, if a scroll up or down very fast the input values swaps its position in another EditText in a RecyclerView.
Before scrolling the data was in the first EditText.
After scrolling up and down the value of the first EditText changed its postion to the 4th one and the swapping is random. Is there any work around to steady the data.

这是一个示例截图

这是模型类:

public class Product {    
    public int pId;    
    public String pName;    
    public double unit_price;    
    public double discount;    
}    

这是适配器类:

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductListHolder> {
Context context;
List<Product> productList;

public ProductAdapter(Context c, List<Product> lp){
    this.context = c;
    this.productList = lp;
}

public class ProductListHolder extends RecyclerView.ViewHolder{
    TextView tvName;
    TextView tvPrice;
    TextView tvDiscount;
    TextView tvTotal;
    EditText etQuantity;
    public ProductListHolder(View itemView) {
        super(itemView);
        tvName = (TextView) itemView.findViewById(R.id.tvName);
        tvPrice = (TextView) itemView.findViewById(R.id.tvPrice);
        tvDiscount = (TextView) itemView.findViewById(R.id.tvDiscount);
        tvTotal = (TextView) itemView.findViewById(R.id.tvTotal);
        etQuantity = (EditText) itemView.findViewById(R.id.etQuantity);
    }
}

@Override
public ProductListHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_row, viewGroup, false);
    ProductListHolder ph = new ProductListHolder(v);
    return  ph;
}

@Override
public void onBindViewHolder(final ProductListHolder productListHolder, final int i) {
    productListHolder.tvName.setText(productList.get(i).pName);
    productListHolder.tvPrice.setText(String.valueOf(productList.get(i).unit_price));
    productListHolder.tvDiscount.setText(String.valueOf(productList.get(i).discount));

    productListHolder.etQuantity.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (!s.toString().equals("")){
                double totalPrice = (productList.get(i).unit_price-productList.get(i).discount)* (Double.valueOf(s.toString()));
                productListHolder.tvTotal.setText(String.valueOf(totalPrice));
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });
}

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

}

这里是 MainActivity:

Here is the MainActivity:

public class MainActivity extends AppCompatActivity {

List<Product> productList;
RecyclerView recyclerView;
RecyclerView.Adapter mAdapter;

String[] names = {"A", "B", "C","D"};
double[] prices = {1000, 2000, 3000, 100};
double[] discounts = {10, 20, 30, 2};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initRecyclerView(); // Initializing Recycler View
    new MyTask().execute();
}

public void initRecyclerView(){
    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
}

private class MyTask extends AsyncTask<Void, Void, List<Product>> {

    @Override
    protected List<Product> doInBackground(Void... params) {
        int sz = 24;
        productList = new ArrayList<Product>();
        for(int i=0; i<sz; i++){
            Product p = new Product();
            p.pId = i%4;
            p.pName = names[i%4];
            p.unit_price = prices[i%4];
            p.discount = discounts[i%4];
            productList.add(p);
        }

        return productList;
    }

    @Override
    protected void onPostExecute(List<Product> products) {
        super.onPostExecute(products);
        mAdapter = new ProductAdapter(MainActivity.this, productList);
        recyclerView.setAdapter(mAdapter);
    }
  }    
}

推荐答案

我已经解决了问题.

问题是我在 onBindViewHolder 中添加了 addTextChangedListener.所以 EditText 中的值总是很混乱,因为当焦点转移时,另一个 addTextChangedListener 被注册了.所以我所做的是,我实现了另一个名为 CustomEtListener 的自定义类并实现了 TextWatcher.所以现在我在 onCreateViewHolder 中为每个 EditText 注册了自定义监听器.并采用 array 字符串来存储编辑文本的值.数组的大小是 RecyclerView 中的项目数.updatePosition 方法用于获取焦点项目的位置.然后 onTextChanged 我只是将 editText 的值存储在数组中,并在 onBindViewHolder 中更新了该 EditText 的值.之后每次滚动时,EditText 的值都不会改变.

I've sorted out the problem.

The problem was that i added the addTextChangedListener in onBindViewHolder. So the values in the EditText always got jumbled, cause when the focus shifted another addTextChangedListener was registered. So what i did is that, i implemented another Custom Class called CustomEtListener and implemented the TextWatcher. So now i registered the custom listener in onCreateViewHolder for each EditText. And took an array of string to store the values of the edit text. And the size of the array was the number of items in the RecyclerView. And the method updatePosition was there to get the position of the focused item. Then onTextChanged i just stored the value of the editText in the array, and updated the value of that EditText in onBindViewHolder. After that every time i scroll, the value of the EditText won't change.

这是我的适配器类.

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductListHolder> {
Context context;
List<Product> productList;
String[] etValArr;
double[] totalValue;

public ProductAdapter(Context c, List<Product> lp) {
    this.context = c;
    this.productList = lp;
    // Create a new array which size matches the number of Edit Texts
    etValArr = new String[productList.size()];
    // and an array for holding all the values of each edit text
    totalValue = new double[productList.size()];
}

public class ProductListHolder extends RecyclerView.ViewHolder {
    TextView tvName;
    TextView tvPrice;
    TextView tvDiscount;
    TextView tvTotal;
    EditText etQuantity;

    // Instance of a Custom edit text listener
    public CustomEtListener myCustomEditTextListener;

    public ProductListHolder(View itemView, CustomEtListener myLis) {
        super(itemView);
        tvName = (TextView) itemView.findViewById(R.id.tvName);
        tvPrice = (TextView) itemView.findViewById(R.id.tvPrice);
        tvDiscount = (TextView) itemView.findViewById(R.id.tvDiscount);
        tvTotal = (TextView) itemView.findViewById(R.id.tvTotal);
        etQuantity = (EditText) itemView.findViewById(R.id.etQuantity);
        // assign a new instance of addTextChangedListener for each item
        myCustomEditTextListener = myLis;
        etQuantity.addTextChangedListener(myCustomEditTextListener);
    }
}

@Override
public ProductListHolder onCreateViewHolder(ViewGroup viewGroup, final int i) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_row, viewGroup, false);
    ProductListHolder ph = new ProductListHolder(v, new CustomEtListener());
    return ph;
}

@Override
public void onBindViewHolder(final ProductListHolder productListHolder, int i) {
    productListHolder.tvName.setText(productList.get(i).pName);
    productListHolder.tvPrice.setText(String.valueOf(productList.get(i).unit_price));
    productListHolder.tvDiscount.setText(String.valueOf(productList.get(i).discount));

    // Update the position when focus changes
    productListHolder.myCustomEditTextListener.updatePosition(i);
    // Setting the values accordingly
    productListHolder.etQuantity.setText(etValArr[i]);
    productListHolder.tvTotal.setText(String.valueOf(totalValue[i]));

}

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

/**
 * Custom class which implements Text Watcher
 */
private class CustomEtListener implements TextWatcher {
    private int position;

    /**
     * Updates the position according to onBindViewHolder
     *
     * @param position - position of the focused item
     */
    public void updatePosition(int position) {
        this.position = position;
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        // Change the value of array according to the position
        etValArr[position] = charSequence.toString();
        // Doing the calculation
        if (!etValArr[position].equals("")) {
            totalValue[position] = (productList.get(position).unit_price - productList.get(position).discount) * (Double.valueOf(etValArr[position]));

        } else {
            totalValue[position] = 0.00;
        }
    }

    @Override
    public void afterTextChanged(Editable editable) {
    }
}
}

我还是有问题.我无法更新 Total 列的值.在我上下滚动之后,值就改变了.所以我必须实现一个回调侦听器来立即获取 Total 列的值.我现在有一个接口 TextCallBackListener,并在 Adapters ProductListHoldersClass 上实现了它.因此,每当调用 onTextChanged 时,它都会触发我的 updateText 方法来更改该行 Total 的值.看不懂的,问题里有截图.

Still i had a problem. I wasn't able to update the Total column's values. After i scroll up and down, then the value changed. So i had to implement a call backListener to get the value of the Total column right away. I have now an interface TextCallBackListener, and implemented it on the Adapters ProductListHoldersClass. So whenever the onTextChanged was called it triggered my updateText method to change the value of that rows Total. if you don't understand the view, there is a screenshot in the question.

这里是TextCallBackListener接口.

Here is the interface TextCallBackListener.

public interface TextCallBackListener {
      public void updateText(String val);
}

这是我更改后的适配器类.

Here is my changed adapter class.

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductListHolder> {
Context context;
List<Product> productList;
String[] etValArr;
double[] totalValue;

public ProductAdapter(Context c, List<Product> lp) {
    this.context = c;
    this.productList = lp;
    // Create a new array which size matches the number of Edit Texts
    etValArr = new String[productList.size()];
    // and an array for holding all the values of each edit text
    totalValue = new double[productList.size()];
}


public class ProductListHolder extends RecyclerView.ViewHolder implements TextCallBackListener {
    TextView tvName;
    TextView tvPrice;
    TextView tvDiscount;
    TextView tvTotal;
    EditText etQuantity;

    // Instance of a Custom edit text listener
    public CustomEtListener myCustomEditTextListener;

    public ProductListHolder(View itemView, CustomEtListener myLis) {
        super(itemView);
        tvName = (TextView) itemView.findViewById(R.id.tvName);
        tvPrice = (TextView) itemView.findViewById(R.id.tvPrice);
        tvDiscount = (TextView) itemView.findViewById(R.id.tvDiscount);
        tvTotal = (TextView) itemView.findViewById(R.id.tvTotal);
        etQuantity = (EditText) itemView.findViewById(R.id.etQuantity);
        // assign a new instance of addTextChangedListener for each item
        myCustomEditTextListener = myLis;
        etQuantity.addTextChangedListener(myCustomEditTextListener);
    }

    @Override
    public void updateText(String val) {
        tvTotal.setText(val);
    }
}


@Override
public ProductListHolder onCreateViewHolder(ViewGroup viewGroup, final int i) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_row, viewGroup, false);
    ProductListHolder ph = new ProductListHolder(v, new CustomEtListener());
    return ph;
}

@Override
public void onBindViewHolder(final ProductListHolder productListHolder, int i) {
    productListHolder.tvName.setText(productList.get(i).pName);
    productListHolder.tvPrice.setText(String.valueOf(productList.get(i).unit_price));
    productListHolder.tvDiscount.setText(String.valueOf(productList.get(i).discount));

    // Update the position when focus changes
    productListHolder.myCustomEditTextListener.updatePosition(i, productListHolder);
    // Setting the values accordingly
    productListHolder.etQuantity.setText(etValArr[i]);
    //productListHolder.tvTotal.setText(String.valueOf(totalValue[i]));

}


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

/**
 * Custom class which implements Text Watcher
 */
private class CustomEtListener implements TextWatcher {
    private int position;
    TextCallBackListener textCallBackListener;

    /**
     * Updates the position according to onBindViewHolder
     *
     * @param position - position of the focused item
     * @param pa       - object of ProductListHolder Class
     */
    public void updatePosition(int position, ProductListHolder pa) {
        this.position = position;
        // assigning it to the instance of the CallBackListener
        textCallBackListener = (TextCallBackListener) pa;
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        // Change the value of array according to the position
        etValArr[position] = charSequence.toString();
        // Doing the calculation
        if (!etValArr[position].equals("")) {
            totalValue[position] = (productList.get(position).unit_price - productList.get(position).discount) * (Double.valueOf(etValArr[position]));
            // triggering the callback function to update the total
            textCallBackListener.updateText(String.valueOf(totalValue[position]));
        } else {
            totalValue[position] = 0.00;
            textCallBackListener.updateText("0.00");
        }
    }

    @Override
    public void afterTextChanged(Editable editable) {

    }

}
}

这篇关于为什么 EditText 中的输入值在 RecyclerView 中滚动时会交换位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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