【问题标题】:Update TextView in selected RecyclerView rows在选定的 RecyclerView 行中更新 TextView
【发布时间】:2017-04-23 13:50:09
【问题描述】:

我在片段中有一个RecyclerView,其中每一行都有一个适配器,它会扩展如下所示的布局:


我想访问每一行的EditText(在下面的代码numberET)的值,如果EditText不为空,则选择该值。
如何我在 RecyclerView 的每个元素上循环(我认为在适配器内部)有这种行为?如何访问每个元素的 EditText 以检索值并在片段中使用它们?

适配器: `

public class UserFBEditTextAdapter <T extends UserFBEditTextAdapter.ViewHolder> extends UserFBAdapter<UserFBEditTextAdapter.ViewHolder>{
public UserFBEditTextAdapter(List<UserFB> users,int layoutId, Context context) {
    super(users, layoutId, context);
}

@Override
public UserFBEditTextAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
    return new UserFBEditTextAdapter.ViewHolder(view);
}

@Override
public void onBindViewHolder(UserFBAdapter.ViewHolder holder, int position) {
    holder.userFB = users.get(position);
    holder.usernameTV.setText(holder.userFB.getName());
}

public class ViewHolder extends UserFBAdapter.ViewHolder {
    protected EditText numberET;

    public ViewHolder(View itemView) {
        super(itemView);
        numberET = (EditText) itemView.findViewById(R.id.number_et);
    }
    }
}`

片段:

public class ExpenseCustomFragment extends Fragment {

private OnFragmentInteractionListener mListener;
private UserFBAdapter adapter;
private RecyclerView userCustomList;

public ExpenseCustomFragment() {
    // Required empty public constructor
}

public static ExpenseCustomFragment newInstance() {
    ExpenseCustomFragment fragment = new ExpenseCustomFragment();

    return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_expense_custom, container, false);

    userCustomList = (RecyclerView) view.findViewById(R.id.amountlist_rv);
    userCustomList.setLayoutManager(new LinearLayoutManager(getContext()));

    NewExpenseDescriptionActivity activity = (NewExpenseDescriptionActivity) getActivity();
    adapter = new UserFBEditTextAdapter(activity.getUsersGroup(),  R.layout.listitem_expensecustom, getContext());

    userCustomList.setAdapter(adapter);


    return view;
}
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}

【问题讨论】:

    标签: android android-fragments android-recyclerview android-adapter


    【解决方案1】:

    您必须将该数据保留在某个基于地图的数据结构中,然后在需要这些值时迭代该数据结构。

    您不能依赖将这些数据保存在ViewHolder 中,因为一旦您执行滚动,ViewHolders 就会被重复使用。如果您当前不保存EditText 中填写的数据,那么如果您有很多项目并执行滚动(即屏幕适合 10 个项目,但您的适配器是 20 个项目,只要您滚动,您就会丢失该数据到第 15 项,第一项的 EditText 值将丢失)。

    private Map<Integer, String> map = new ArrayMap<>(adapterSize);
    
    ...
    
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        String text = map.get(holder.getAdapterPosition());
        // maybe we haven't yet saved text for this position
        holder.editText.setText(text != null ? text : "");
        // updated value in map as soon as the `EditText` in this position changes
        holder.editText.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) {
                map.put(holder.getAdapterPosition(), s.toString());
            }
    
            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    }
    

    现在您可以访问您的RecyclerView 中的所有EditText 值。您可以考虑的唯一更改是在用户停止输入后更新地图。目前,如果用户输入“123456789”,地图将更新 9 次,而我们只需要一次。一个简单的解决方案是使用 RxJavadebounce operator 结合 RxBinding 库。这听起来可能很复杂,但你可以看到它是多么简单in this answer

    这会奏效。但是在你来回滚动之后,你很快就会发现那里发生了一些混乱。这是因为每次调用onBindViewHolder() 时,都会将一个新的TextWatcher 添加到已经附加了TextWatcherEditText。因此,在您的ViewHolder 被回收后,您还必须注意删除TextWatcher

    但是没有一个 API 可以删除 EditText 中的所有 TextWatcher。您可以使用this answer 中显示的自定义EditText 实现,它将清除附加到此EditText 的所有TextWatcher

    @Override
    public void onViewRecycled(MyViewHolder holder) {
        holder.editText.clearTextChangeListeners();
        super.onViewRecycled(holder);
    }
    

    【讨论】:

    • 谢谢!因此,如果从RecyclerView 检索持有人,由于RecyclerView 中的项目数量很大,我会遇到同样的问题。
    • 无法理解您的意思。你能解释一下吗?
    • 我的意思是,我通过recyclerView.findViewHolderForLayoutPosition(position)从给定位置关联的持有人RecyclerView获取。如果我在RecyclerView 中包含的ViewHolder 上循环,并且RecyclerView 有例如20 个项目,而我的Fragment 一次只能显示4 个项目,我将丢失EditText 的内容,它们是不显示。我做对了吗?
    • 感谢您的解释!
    猜你喜欢
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多