Waseem
Waseem

Reputation: 527

How to implement scroll function like Uber Eats Food Menu scroll

SORRY FOR THE BAD QUESTION TITLE, I DON'T KNOW HOW TO NAME THIS FEATURE

I am developing a small food ordering application, for that I am implementing scroll feature.

  1. I have 2 recycler views, 1st contains food list 2nd contains food categories list
  2. Each and every food list item always having its category name
  3. food list is vertically scrollable and food category list horizontally scrollable.

What my problem is,

  1. When I refresh foods recycler view, category recycler view items getting highlight one by one for each refresh. Here the image
  2. When I scroll foods recycler view category items automatically need to highlight like when how I click category item.

I attached a video clip for exactly what I am expecting. Here is the video

If anyone can, please help me. Thank you.

This is my Foods class (FoodMenuFragment.java)

public class FoodMenuFragment extends Fragment implements View.OnClickListener {

    private OnFragmentInteractionListener mListener;

    Typeface fontSemiBold;
    private static View view;
    private static RecyclerView listRecyclerView;
    private List<String> listCategoryName = new ArrayList<>();
    public static List<MenuFoods> foodListCategory = new ArrayList<>();
    private static List<MenuFoodsCategory> listArrayList = new ArrayList<>();
    public static foodsAdapter adapterFoods;

    private boolean userScrolled = true;
    int pastVisiblesItems, visibleItemCount, totalItemCount;
    private String udToken = "", restId = "";
    SessionManager session;

    TwoWayView listCategory;
    private static LinearLayoutManager mLayoutManager;
    private RecyclerView recyCategory;
    private int selectedPosition = -1;
    LinearLayoutManager layoutManager;

    private SwipeRefreshLayout swipeRefreshLayout;
    LinearLayout lineNoOffer, lineServerError;
    TextView tvServerError;
    private Dialog progressDialog;


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


        session = new SessionManager(getApplicationContext());

        swipeRefreshLayout = view.findViewById(R.id.swipe_refresh);
        lineNoOffer = view.findViewById(R.id.lineNoOffer);
        listCategory = view.findViewById(R.id.listCategory);
        //Initialize category horizontal view
        recyCategory = view.findViewById(R.id.recyCategory);
        recyCategory.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
        recyCategory.setLayoutManager(layoutManager);
        recyCategory.swapAdapter(new categoryAdapterNew(getApplicationContext(), listCategoryName), true);


        if (isAdded()) {
            init();
            listArrayList.clear();
            listCategoryName.clear();
            foodListCategory.clear();
            getFood();
        }
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if (isAdded()) {
                    listArrayList.clear();
                    listCategoryName.clear();
                    foodListCategory.clear();
                    getFood();
                }
                swipeRefreshLayout.setRefreshing(false);
            }
        });

        listCategory.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //Toast.makeText(getContext(), "click"+String.valueOf(position), Toast.LENGTH_SHORT).show();
                String tmpCatego = "", tmpCategoId = "";

//             for (int i = 0; i < listCategoryName.size(); i++){
                tmpCatego = listCategoryName.get(position);
//             }
                for (int j = 0; j < listArrayList.size(); j++) {
                    if (tmpCatego.trim().toLowerCase().equals(listArrayList.get(j).getCategoryName().trim().toLowerCase())) {
                        tmpCategoId = listArrayList.get(j).getCategoryId();
                        break;
                    }
                }

                for (int i = 0; i < foodListCategory.size(); i++) {
                    if (tmpCategoId.equals(foodListCategory.get(i).getCategoryId())) {
                        listRecyclerView.smoothScrollToPosition(i);
                    }
                }
            }
        });

        recyCategory.addOnItemTouchListener(new RecyclerTouchListener(getContext(), recyCategory, new RecyclerTouchListener.ClickListener() {
            @Override
            public void onClick(View view, int position) {

                //Toast.makeText(getContext(), "click"+String.valueOf(position), Toast.LENGTH_SHORT).show();
                String tmpCatego = "", tmpCategoId = "";

//             for (int i = 0; i < listCategoryName.size(); i++){
                tmpCatego = listCategoryName.get(position);
//             }
                for (int j = 0; j < listArrayList.size(); j++) {
                    if (tmpCatego.trim().toLowerCase().equals(listArrayList.get(j).getCategoryName().trim().toLowerCase())) {
                        tmpCategoId = listArrayList.get(j).getCategoryId();
                        break;
                    }
                }

                for (int i = 0; i < foodListCategory.size(); i++) {
                    if (tmpCategoId.equals(foodListCategory.get(i).getCategoryId())) {
                        listRecyclerView.smoothScrollToPosition(i);
                    }
                }

            }

            @Override
            public void onLongClick(View view, int position) {

            }
        }));

        final int[] count = {0};
        listRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);


            }

            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                if (isAdded()) {
                    try {

                        if (count[0] == 0) {


                            if (newState == RecyclerView.SCROLL_STATE_IDLE) {

                            }
//                      Toast.makeText(getContext(), "position "+ String.valueOf(firstVisiblePosition[0]), Toast.LENGTH_SHORT).show();
                            View visibleChild = recyclerView.getChildAt(0);
                            int positionOfChild = recyclerView.getChildAdapterPosition(visibleChild);
                            String tmpCatego = foodListCategory.get(positionOfChild).getCategoryName();

                            for (int k = 0; k < listCategoryName.size(); k++) {
                                if (tmpCatego.trim().toLowerCase().equals(listCategoryName.get(k).trim().toLowerCase())) {
                                    recyCategory.smoothScrollToPosition(k);

                                    View view = layoutManager.findViewByPosition(k);
                                    categoryAdapterNew.highlightView(view, positionOfChild);
                                }
                            }

                            count[0]++;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });


//        SnapHelper helper = new LinearSnapHelper(){
//            @Override
//            public View findSnapView(RecyclerView.LayoutManager layoutManager) {
//                View view = super.findSnapView(layoutManager);
//                try {
//                    if(view != null){
//                        final int newPos = layoutManager.getPosition(view);
//
//                        if(newPos != selectedPosition && listRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE){
//                            selectedPosition = newPos;
//
//                            for (int j = 0; j < foodListCategory.size(); j++){
//                                if(foodListCategory.get(j).getCategoryId().trim().equals(foodListCategory.get(selectedPosition).getCategoryId())){
////                                    int categoPos = ;
//                                    for (int k = 0; k < listCategoryName.size(); k++){
//
//                                    }
//                                }
//                            }
//                        }
//                    }
//                }catch (Exception e){
//                    e.printStackTrace();
//                }
//                return view;
//            }
//        };
//        helper.attachToRecyclerView(listRecyclerView);

        return view;
    }


    private void init() {

        mLayoutManager = new LinearLayoutManager(getActivity());
        listRecyclerView = (RecyclerView) view.findViewById(R.id.linear_recyclerview);
        listRecyclerView.setHasFixedSize(true);
        listRecyclerView.setLayoutManager(mLayoutManager);// for

    }

    public void getFood() {
        progressDialog.show();

        ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
        Call<MenuFoodsResponse> call = apiInterface.getRestaurantMenuFood(restId, "foods", udToken);

        call.enqueue(new Callback<MenuFoodsResponse>() {
            @Override
            public void onResponse(@NonNull Call<MenuFoodsResponse> call, @NonNull Response<MenuFoodsResponse> response) {

                try {

                    String travelType = "";
                    if (response.body() == null) {

                    } else if (response.body().getCode() == 200) {      //If user not registered

                        listArrayList = response.body().getContent();

                        if (listArrayList.size() > 0) {

                            for (int j = 0; j < listArrayList.size(); j++) {
                                foodListCategory.addAll(listArrayList.get(j).getContent());
                                for (int k = 0; k < foodListCategory.size(); k++) {

                                    if (!listCategoryName.contains(listArrayList.get(j).getCategoryName())) {
                                        listCategoryName.add(listArrayList.get(j).getCategoryName());
                                    }

                                    if (foodListCategory.get(k).getCategoryId() == null) {
                                        foodListCategory.get(k).setCategoryId(listArrayList.get(j).getCategoryId());
                                        foodListCategory.get(k).setCategoryName(listArrayList.get(j).getCategoryName());
                                    }
                                }
                            }
                            adapterFoods = new foodsAdapter(getActivity(), foodListCategory);
                            listRecyclerView.setAdapter(adapterFoods);
                            adapterFoods.notifyDataSetChanged();

                            //Show Category list
//                            categoryAdapter myAdapter1 = new categoryAdapter(getContext(), R.layout.custom_category_list_item, listCategoryName);
//                            listCategory.setAdapter(myAdapter1);

                            recyCategory.swapAdapter(new categoryAdapterNew(getApplicationContext(), listCategoryName), true);

                            lineNoOffer.setVisibility(View.GONE);
                        } else {
                            lineNoOffer.setVisibility(View.VISIBLE);
                        }

                    } else {        //If user already registered

                        String errorMessage = response.body().getMessage();
                        String errorCode = response.body().getErrorCode();
                        Toast.makeText(getActivity(), errorMessage + "(" + errorCode + ")", Toast.LENGTH_SHORT).show();

                    }

                    progressDialog.dismiss();
                } catch (Exception e) {
                    e.printStackTrace();
                    progressDialog.dismiss();
                }
            }

            @Override
            public void onFailure(@NonNull Call<MenuFoodsResponse> call, @NonNull Throwable t) {
                Log.e("TAG", t.toString());
                t.printStackTrace();
                Toast.makeText(getApplicationContext(), "Error :" + t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
                progressDialog.dismiss();
            }
        });

    }

    @Override
    public void onClick(View v) {

    }
}

This is Food layout (fragment_food_menu.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.urbandine.home.FoodMenuFragment">

    <!-- TODO: Update blank fragment layout -->

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <android.support.v7.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/recyCategory"
                android:background="@color/white_color"
                android:layout_alignParentTop="true"/>

            <android.support.v7.widget.RecyclerView
                android:layout_below="@+id/recyCategory"
                android:id="@+id/linear_recyclerview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/light_grey_color" />

        </RelativeLayout>

</LinearLayout>

This is foods adapter class (foodsAdapter.java)

public class foodsAdapter extends RecyclerView.Adapter<FoodsViewHolder>  {

    private List<MenuFoods> arrayList;
    private List<MenuFoods> arrayListFiltered;
    private Context context;
    private LinearLayout lineSmall, lineMedium, lineLarge;
    private TextView tvPriceSmall, tvPriceMedium, tvPriceLarge, tvDishCount1, tvDishCount2, tvDishCount3;
    private ImageView ivAddSmall, ivAddMedium, ivAddLarge, ivRemoveSmall, ivRemoveMedium, ivRemoveLarge;


    public foodsAdapter(Context context, List<MenuFoods> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
        this.arrayListFiltered = arrayList;
    }

    @Override
    public int getItemCount() {
        return (null != arrayListFiltered ? arrayListFiltered.size() : 0);
    }

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

        if (arrayListFiltered.size() > 0) {

            final MenuFoods model = arrayListFiltered.get(position);

                    FoodsViewHolder mainHolder = (FoodsViewHolder) holder;// holder

               }
            }

            // Implement click listener over layout
            mainHolder.setOnClickListener(new OnRecyclerItemClickListener() {
                @Override
                public void onItemClickListener(View v, int pos) {
                    switch (v.getId()) {
                        case R.id.mainDrinks:

                            Activity activity = (Activity) context;

                            Intent intent = new Intent(context, DishDetailActivity.class);
                            context.startActivity(intent);
                            activity.overridePendingTransition(R.anim.push_right_out, R.anim.push_right_in);

                            break;
                    }
                }
            });

        }
    }

    @Override
    public FoodsViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        // This method will inflate the custom layout and return as viewholder
        LayoutInflater mInflater = LayoutInflater.from(viewGroup.getContext());

        ViewGroup mainGroup = (ViewGroup) mInflater.inflate(R.layout.custom_foods_item, viewGroup, false);
        FoodsViewHolder listHolder = new FoodsViewHolder(mainGroup);
        return listHolder;

    }

}

My category view adapter (categoryAdapterNew.java)

public class categoryAdapterNew extends RecyclerView.Adapter<categoryAdapterNew.CategoViewHolder> {

    private List<String> amiItem = new ArrayList<>();
    Context context;
    private static Context context1;
    private static TextView lastChecked = null;

    public class CategoViewHolder extends RecyclerView.ViewHolder {

     TextView textView;

        public CategoViewHolder(View view) {
            super(view);
            textView = view.findViewById(R.id.tvCuisine);
        }
    }

    public categoryAdapterNew(Context context, List<String> categoList) {
        this.context = context;
        this.amiItem = categoList;
        this.context1 = context;
    }

    @NonNull
    @Override
    public categoryAdapterNew.CategoViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.custom_category_list_item, viewGroup, false);

        return new categoryAdapterNew.CategoViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull categoryAdapterNew.CategoViewHolder holder, int i) {
        if(amiItem.size() > 0){

            holder.textView.setText(amiItem.get(i));

            //for default highlight first item on category recycler view
            if(i == 0 && !holder.textView.isSelected()){

                lastChecked = holder.textView;
                lastCheckedPos  = 0;
                lastChecked.setTextColor(context1.getResources().getColor(R.color.red_color));
                lastChecked.setSelected(true);
            }

            //Highlight textView when click on category item
            holder.textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    TextView tv = (TextView)v;
                    int clickPos = -1;

                    for(int k = 0; k < amiItem.size(); k++){
                        if(tv.getText().toString().trim().toLowerCase().equals(amiItem.get(k).trim().toLowerCase())){
                            clickPos = k;
                            break;
                        }
                    }

                    if(!tv.isSelected()){
                        if(lastChecked != null){
                            lastChecked.setSelected(false);
                            lastChecked.setTextColor(context1.getResources().getColor(R.color.text_color));
                        }
                        lastChecked = tv;
                        tv.setSelected(true);
                        tv.setTextColor(context1.getResources().getColor(R.color.red_color));
                        lastCheckedPos = clickPos;
                    }
                }
            });
        }
    }

    //Highlight category item when scroll dish recycler view
    public static void highlightView(View view, int pos){
        TextView textView = (TextView)view.findViewById(R.id.tvCuisine);

        if(!textView.isSelected()){
            if(lastChecked != null){
                lastChecked.setSelected(false);
                lastChecked.setTextColor(context1.getResources().getColor(R.color.text_color));
            }
            lastChecked = textView;
            textView.setSelected(true);
            textView.setTextColor(context1.getResources().getColor(R.color.red_color));
            lastCheckedPos = pos;
        }
    }

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

Upvotes: 0

Views: 1431

Answers (1)

Vrushi Patel
Vrushi Patel

Reputation: 2441

It's simple you have to take two different layouts tab-layout in horizontal scroll and vertical scroll-view for items when user scroll to particular point tab need to be selected and tab-layout to be visible.

Upvotes: 1

Related Questions