嵌套的 RecyclerView 处理 onClick

Nested RecyclerView handling onClick

我有一个片段,它有一个嵌套的 RecyclerView 来显示产品列表。我根据 mmlooloo 的解决方案实现了这一点:How to create scrollable page of carousels in Android?

这是我的片段,我在其中调用了 MainRecyclerProductAdapter

public class CashSaleFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private static final String TAG = "MainActivity";
private UserPreference userPreference = new UserPreference();
int numOfRows = 11;
int numOfColumns = 8;
public int layout = 1; // 0-list_icon 1-list 2-grid_icon 3-grid
public List<Product> listProduct, listProductFilter;
private DatabaseHelper db;
private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
View view;
Activity activity;

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

private OnFragmentInteractionListener mListener;

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

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment CashSaleFragment_old.
 */
// TODO: Rename and change types and number of parameters
public static CashSaleFragment newInstance(String param1, String param2) {
    CashSaleFragment fragment = new CashSaleFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}

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

    activity = getActivity();
    userPreference.init(activity);
    db = DatabaseHelper.getInstance(activity);

    // Get layout setting value
    layout = Integer.parseInt(userPreference.getStringShared(SysPara.POS_LAYOUT));

    changeViewProductAll();

    return view;
}

public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.cash_sale, menu);
    super.onCreateOptionsMenu(menu,inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    return super.onOptionsItemSelected(item);
}

/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}

// Get all products
private List<Product> getProducts(String tms_id, String user_co_id) {
    return db.getAllProduct(tms_id, user_co_id);
}

// Convert to ListofListofProduct
private List<List<Product>> toListofListProduct(List<Product> product, int listSize, int row, int col) {
    List<List<Product>> listOfListOfProducts = new ArrayList<List<Product>>();
    int index = 0;
    // if listing, change layout to contain only 1 column in each row
    if (layout == 0 || layout == 1) {
        row = product.size();
        col = 1;
    }

    for(int i = 0 ; i<row ; i++){
        List<Product> listOfProducts = new ArrayList<Product>();
        for(int j = 0 ; j<col ; j++){
            if (listSize == index) {
                listOfListOfProducts.add(listOfProducts);
                return listOfListOfProducts;
            }
            listOfProducts.add(product.get(index));
            index++;
        }
        listOfListOfProducts.add(listOfProducts);
    }
    return listOfListOfProducts;
}

// Change the viewing display of product: list, listIcon, grid, gridIcon
public void changeViewProductAll() {
    mRecyclerView = (RecyclerView) view.findViewById(R.id.rv_product);
    mRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(activity));
    mLayoutManager = new LinearLayoutManager(activity,LinearLayoutManager.VERTICAL,false);
    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.setHasFixedSize(true);

    //creation of the products for the grid/list
    listProduct = new ArrayList<Product>();
    listProductFilter = new ArrayList<Product>();

    listProduct = getProducts(userPreference.getStringShared(SysPara.TMS_ID), userPreference.getStringShared(SysPara.USER_CO_ID));
    List<List<Product>> ListofListofProducts = toListofListProduct(listProduct, listProduct.size(), numOfRows, numOfColumns);

    Fragment fragment = new CashSaleFragment();
    MainRecyclerProductAdapter mainRecyclerProductAdapter = new MainRecyclerProductAdapter(ListofListofProducts,activity,fragment);
    mRecyclerView.setAdapter(mainRecyclerProductAdapter);
}

这是MainRecyclerProductAdapter

public class MainRecyclerProductAdapter extends RecyclerView.Adapter<MainRecyclerProductAdapter.ViewHolder> {

public static final String LOGTAG ="MainRecyclerProductAdapter";
private List<List<Product>> mRows;
Context mContext;
Fragment mFragment = new CashSaleFragment();
public MainRecyclerProductAdapter(List<List<Product>> objects, Context context, Fragment fragment) {
    mContext = context;
    mRows = objects;
    mFragment = fragment;
}

static class ViewHolder extends RecyclerView.ViewHolder{
    public  RecyclerView mRecyclerViewRow;
    public ViewHolder(View itemView) {
        super(itemView);
        mRecyclerViewRow =(RecyclerView)itemView.findViewById(R.id.recyclerView_row);
    }
}

@Override
public int getItemCount() {

    return mRows.size();
}

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

    List<Product> RowItems = mRows.get(position);
    LinearLayoutManager layoutManager = new LinearLayoutManager(mContext,LinearLayoutManager.HORIZONTAL,false);     
    holder.mRecyclerViewRow.setLayoutManager(layoutManager);
    holder.mRecyclerViewRow.setHasFixedSize(true);
    RowRecyclerProductAdapter rowsRecyclerAdapter = new RowRecyclerProductAdapter(mContext,RowItems,mFragment);
    holder.mRecyclerViewRow.setAdapter(rowsRecyclerAdapter);
}


@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
    LayoutInflater inflater =    
            (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    View convertView = inflater.inflate(R.layout.recyclerview_row, parent, false);
    return new ViewHolder(convertView);
}

RowRecyclerProductAdapter

public class RowRecyclerProductAdapter extends RecyclerView.Adapter<RowRecyclerProductAdapter.ViewHolder> {

private OnItemClickListener onItemClickListener;
private List<Product>  mItems, productClickList;
private UserPreference userPreference = new UserPreference();
private int layout;
Context mContext;
com.m3online.i3twpos.util.OnItemClickListener onItemClickListener;
Fragment mFragment = new CashSaleFragment();
final Handler handler = new Handler();
public RowRecyclerProductAdapter(Context context, List<Product> objects, Fragment fragment) {
    mContext = context;
    mItems = objects;
    mFragment = fragment;

    userPreference.init(mContext);
    layout = Integer.parseInt(userPreference.getStringShared(SysPara.POS_LAYOUT));


}

static class ViewHolder extends RecyclerView.ViewHolder{
    public ImageView mImageView;
    public TextView mTextView, mSKU;
    public View rootView;
    public ViewHolder(View itemView) {
        super(itemView);
        rootView = itemView;
        mImageView =(ImageView)itemView.findViewById(R.id.productIcon);
        mTextView =(TextView)itemView.findViewById(R.id.productTitle);
        mSKU =(TextView)itemView.findViewById(R.id.sku);
    }
}

@Override
public int getItemCount() {

    return mItems.size();
}

public RowRecyclerProductAdapter (com.m3online.i3twpos.util.OnItemClickListener onItemClickListener) {
    this.onItemClickListener = onItemClickListener;
}

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
    final ViewHolder vh = (ViewHolder) holder;

    final Product product = mItems.get(position);

    holder.mTextView.setText(product.getProduct_name());
    holder.mSKU.setText(product.getProduct_sku());

    vh.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(mContext, "Click "+holder.mTextView.getText().toString(), Toast.LENGTH_SHORT).show();

            onItemClickListener.onItemClick(product);
        }
    });
}

public interface OnItemClickListener {
    void onItemClick(Product product);
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    View convertView = inflater.inflate(R.layout.product_grid, parent, false);
    return new ViewHolder(convertView);
}

使用此实现,我可以单击并访问每个 ViewHolder,但我无法将数据传递到我的片段。这是因为我想将点击的项目添加到另一个列表(productOrderList),并将其显示在 ListView 中。作为现在的解决方法,我将单击的 Product 放入 SharedPreferences,然后再次加载我的片段。

这样,我可以从 SharedPreferences 获取列表并显示我的 ListView,但我想采取适当的方式来处理这种情况。我对编程真的很陌生,但每天仍在学习很多东西。真的希望你们能帮我解决这个问题。

抱歉,如果我的解释不够清楚,如果我还需要添加其他细节,请告诉我。

编辑:

Screenshot of my current app

橙色框是我的 MainRecyclerProductAdapter,而绿色框是每行的 RowRecyclerProductAdapter。我想要实现的是,一旦我单击 RecyclerView 中列出的任何 Product,我希望将其添加到 productOrderList 中并在紫色框中生成一个 ListView .

这将解决您的问题:但我无法将数据传递到我的片段

您可以添加一个以对象作为参数的接口,通过使用它,您现在可以将数据从适配器传递到片段并将其用于您的:并将其显示在 ListView 中 问题。

CashSaleFragment

MainRecyclerProductAdapter mainRecyclerProductAdapter = new MainRecyclerProductAdapter(ListofListofProducts,activity,fragment, new com.m3online.i3twpos.util.OnItemClickListener() {
    @Override
    public void onItemClick(Product product) {
        //you can now handle the product that is clicked from here on fragment. yey!
    }
});

MainRecyclerProductAdapter

public static final String LOGTAG ="MainRecyclerProductAdapter";
private List<List<Product>> mRows;
Context mContext;
Fragment mFragment = new CashSaleFragment();
om.m3online.i3twpos.util.OnItemClickListener onItemClickListener; //add this

//update your constructor, add your custom interface
public MainRecyclerProductAdapter(List<List<Product>> objects, Context context, Fragment fragment, com.m3online.i3twpos.util.OnItemClickListener onItemClickListener) {
    mContext = context;
    mRows = objects;
    mFragment = fragment;
    this.onItemClickListener = onItemClickListener; //add this
}

.....

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

    List<Product> RowItems = mRows.get(position);
    LinearLayoutManager layoutManager = new LinearLayoutManager(mContext,LinearLayoutManager.HORIZONTAL,false);     
    holder.mRecyclerViewRow.setLayoutManager(layoutManager);
    holder.mRecyclerViewRow.setHasFixedSize(true);
    RowRecyclerProductAdapter rowsRecyclerAdapter = new RowRecyclerProductAdapter(mContext, RowItems, mFragment, onItemClickListener);
    holder.mRecyclerViewRow.setAdapter(rowsRecyclerAdapter);
}

RowRecyclerProductAdapter

public RowRecyclerProductAdapter(Context context, List<Product> objects, Fragment fragment, com.m3online.i3twpos.util.OnItemClickListener onItemClickListener) {
    mContext = context;
    mItems = objects;
    mFragment = fragment;

    userPreference.init(mContext);
    layout = Integer.parseInt(userPreference.getStringShared(SysPara.POS_LAYOUT));

    this.onItemClickListener = onItemClickListener; //add this, to get the interface passed from fragment to mainrecyclerproductadapter to here
}

首先,您需要一个界面来拦截内部 recyclerview 中的触摸事件,因此在内部像这样创建一个 class。它会将截获的任何触摸传回给调用 class 的父级。

public class ItemClickSupport {

private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mOnItemClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
    }
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        if (mOnItemLongClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
        return false;
    }
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener =
        new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(View view) {
                if (mOnItemClickListener != null) {
                    view.setOnClickListener(mOnClickListener);
                }
                if (mOnItemLongClickListener != null) {
                    view.setOnLongClickListener(mOnLongClickListener);
                }
            }

            @Override
            public void onChildViewDetachedFromWindow(View view) {

            }
        };

private ItemClickSupport(RecyclerView recyclerView) {
    mRecyclerView = recyclerView;
    mRecyclerView.setTag(R.id.item_click_support, this);
    mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}

public static ItemClickSupport addTo(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support == null) {
        support = new ItemClickSupport(view);
    }
    return support;
}

public static ItemClickSupport removeFrom(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support != null) {
        support.detach(view);
    }
    return support;
}

public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
    mOnItemClickListener = listener;
    return this;
}

public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
    mOnItemLongClickListener = listener;
    return this;
}

private void detach(RecyclerView view) {
    view.removeOnChildAttachStateChangeListener(mAttachListener);
    view.setTag(R.id.item_click_support, null);
}

public interface OnItemClickListener {

    void onItemClicked(RecyclerView recyclerView, int position, View v);

    void onItemClicked(int position);
}

public interface OnItemLongClickListener {

    boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}

public static class SimpleOnItemClickListener implements OnItemClickListener {

    @Override
    public void onItemClicked(int position) {

    }

    @Override
    public void onItemClicked(RecyclerView recyclerView, int position, View v) {

    }
}

}

现在,当您创建外部 recyclerview 适配器时,只需初始化它即可。

ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(this);

这时候你将拥有拦截你在外部适配器 class.

中作为 this 传递的内部触摸事件所需的所有方法

但我们也希望这些事件从外部适配器 class 传递到调用片段,设置一个像这样的侦听器。

rootAdapter.setOnItemClickListener(this);

现在在根适配器中,绑定项目和创建内部适配器时,将项目点击支持监听器传递给内部适配器,如下所示:

    innerAdapter.setOnItemClickListener(new ItemClickSupport.SimpleOnItemClickListener() {
    @Override
    public void onItemClicked(int position) {
        // Here we pass the click to the parent provided click listener.
        // We modify the position with the one of the ViewHolder so that we don't get the
        // position of the horizontal RecyclerView adapter - we are interested on the
        // vertical item actually.
        if (null != mItemClickListener) {
            mItemClickListener.onItemClicked(holder.getAdapterPosition());
        }
    }
});

mItemClickListener就是你上面通过fragment设置的。

在内部适配器中,创建视图时,在布局的根部设置一个点击监听器,并将该事件传回自定义点击监听器:

    // Detect the click events and pass them to any listeners
itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (null != mOnItemClickListener) {
            mOnItemClickListener.onItemClicked(position);
        }
    }
});

mOnItemClickListener其实就是上面说的adapter传递过来的item点击支持