Search code examples
androidlistviewandroid-fragmentsandroid-recyclerviewnestedrecyclerview

Nested RecyclerView handling onClick


I have a fragment which has a nested RecyclerView to display list of products. I implement this as per this solution by mmlooloo : How to create scrollable page of carousels in Android?

This is my fragment where I called my 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);
}

This is the 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);
}

With this implementation, I could click and have access to each ViewHolder, but I could not pass the data to my fragment. This is because I would like to add the clicked item to another list(productOrderList), and display it in a ListView. As a workaround now, I put the clicked Product into SharedPreferences and then load my fragment again.

This way, I can get the list from SharedPreferences and display my ListView, but I want to do a proper way of handling this type of situation. I'm really new to programming and still learning a lot of things on a daily basis. Really hope you guys could help me out on this.

Sorry if my explanation is not clear enough, please let me know if I need to add other details as well.

EDIT :

Screenshot of my current app

The orange box is my MainRecyclerProductAdapter while the box with green color is the RowRecyclerProductAdapter for each row. What I want to achieve is, once I clicked on any of the Product listed in my RecyclerView, I want it to be added into a productOrderList and generate a ListView in the box color purple.


Solution

  • This will solve your problem: but I could not pass the data to my fragment

    You can add an interface with the object as parameter, and by using this, you can now pass the data from your adapter to the fragment and use it for your: and display it in a ListView problem.

    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
    }